<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="keywords" content="Hexo Theme Redefine">
    
    <meta name="author" content="xiaoeryu">
    <!-- preconnect -->
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

    
    <!--- Seo Part-->
    
    <link rel="canonical" href="https://xiaoeeyu.github.io/2022/12/11/31-分页和动态页面分配/"/>
    <meta name="robots" content="index,follow">
    <meta name="googlebot" content="index,follow">
    <meta name="revisit-after" content="1 days">
    
    
    
        
        <meta name="description" content="01. 保护模式下的段式虚拟内存管理">
<meta property="og:type" content="article">
<meta property="og:title" content="分页和动态页面分配">
<meta property="og:url" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/index.html">
<meta property="og:site_name" content="xiaoeryu">
<meta property="og:description" content="01. 保护模式下的段式虚拟内存管理">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/62bfe0734f409c5d5c8112070c36e1c1-16683301558173.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/036caff772c8fd8009a012aaf154b714-16683301558161.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/fe2e91264c510777c1f5ab83f4ed81e3-16683301558172.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/3a4cfb5324b487b51a585fe54fc56503-16683301558174.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/bb0b37403a3132f2c94521f606306756-16683301558175.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/7926fbcef13874a2671f401b9a37b35f-16683301558176.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/584e40306c3dc5a8a811fe0e018ba3d2-16683301558178.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/34904d9c5835832a2e72d6ea283c84ff-16683301558177.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/d47a393d2fdb43c0a19a9c42d2c3e708-16683301558179.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/c75045c9e153d106f0ee9c46e78b4d21-166833015581710.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/6bbc331d521c2b23008955260caf01da-166833015581712.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/93616ac55c672e94aecb012e18395328-166833015581713.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/36a2e0300007314f584d45006d3de7ad-166833015581711.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/5287f633388a52beac4c4258391c5a66-166833015581715.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/885d06e0f92aa2df15899b4f9094e35a-166833015581714.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/340687599ee7c41b66cadb4e85366328-166833015581717.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/ccb29b4b220f40bfa03a583e0251bfd4-166833015581716.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/93b5bdef561fe3821708a0f77fa511f9-166833015581718.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/b1f267f0104a6773190214d35953bd65-166833015581719.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/0b3f8e4539156e697b30c8330722dcef-166833015581721.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/079466d3ffa8514574fe5a7827cc4ff0-166833015581722.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/b771000981bd8fddea1731849f08ee2a-166833015581720.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/4defd07ca51dd0f680870b47b4bd5557-166833015581724.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/6c560a13f33c3a4ab7c0e856e07fce62-166833015581723.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/a89f73cb347d517ecd51ad35d5df478d-166833015581725.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/beb5acd012b007f792699b63338eff0f-166833015581727.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/763bc09ba5fc0f5dd61cd15b5c4af155-166833015581726.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/fcf277bc282630c1024cc9525453f59f-166833015581829.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/c7312b043bc27fce971c77a8debceca8-166833015581831.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/92e225986b4e3925e3d7e7642af46952-166833015581828.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/419baf206d393622a45a6df21ff7a1db-166833015581830.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/f045a9fa5ce5ccbb02648df2229d15a8-166833015581832.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/234c965b022ff7b6681224e3a0062c63-166833015581833.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/014976f410021c0c1e7c7413cd1827fb-166833015581836.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/e3c365f0007bf5d9b3833567346b3f4c-166833015581834.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/1cdef7a86047f1863b9f3ce7742d262d-166833015581835.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/54d5c6a1dbf186708bbbdb66410eee24-166833015581837.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/b1c16fc5f1bca227f50ff84a7bd875e7-166833015581839.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/6ccae13d834791c7061285a74c59a792-166833015581838.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/aecb11d2fe5887c73f36b8b825ac5b1b-166833015581840.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/6c70462626d0d82f01f81c56083debb5-166833015581842.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/9b4f60cf5f2e43889d5600832c6904b4-166833015581841.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/d098a012924babbbd497fd1eccabb229-166833015581843.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/67b42d52f153a06592223adf2b7f4d47-166833015581845.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/0c417599ea065eef914819e2e1793415-166833015581844.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/acf80d1de43efe9f041004f4a3b904b0-166833015581846.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/3ad1df59914bba12be726e1ae66c5926-166833015581847.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/9fc5d96dbc0a1504600ba8e77bb2b9b7-166833015581848.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/b6c561c38b70ea1b53dae22737bdfce1-166833015581849.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/91a65c1fdf8d13e23c1bd7ec0059820a-166833015581850.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/08ee83725bed57df523f887bad4feb86-166833015581851.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/a3b525b67a8d9b517437736e9ae5353f-166833015581852.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/7b5c22e8ad8cf86185d4ec963a28e64a-166833015581853.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/272b36f0833457b2c03537b9216d8e1f-166833015581854.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/a05d401b9a96a903b54d20c9fb3d038a-166833015581855.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/0fd5c986eb285833f1dfcfffe044b0ac-166833015581856.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/e66f60ea08bb0e11cc9de0dd2e497b7a-166833015581857.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/13f99b6ba093a2a18cba25f1489a24ab-166833015581858.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/6a69e2857945ee2dba5b35e8cc22619f-166833015581859.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/656dfa078ff57ba75bd187ffe33d9b41-166833015581860.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/3dcec8f0d43ee50f8db16c63509ea2dc-166833015581861.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/194209671b306b8380b601d6be27d590-166833015581862.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/5837f70290e6bb72a757e1bcef580a32-166833015581863.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/aca041c9ac0123cdb24af86c9edcd428-166833015581864.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/dd2b5a8684bfc62701272aea8478fbf0-166833015581865.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/6fd5cdbb83920e3cf30528b36302925c-166833015581866.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/349244ce1593efe244c1b0adc27561fd-166833015581867.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/f4f000bbf6183222289074429bf531a0-166833015581868.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/07556a53fea08215d82d60162499308e-166833015581969.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/fc207a4863236bff10f6dae579f1fc5e-166833015581970.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/86a5e81c6f38a69aa6a7f214ed2c8fd9-166833015581971.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/70d154c87cbdd47bdabab6d6f7a1f256-166833015581972.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/944f6f04ee6e0be26a785c13e719da30-166833015581973.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/dd6b2d1cf65101ab1157fdbf959c2e12-166833015581974.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/7c427b058ef8287c6591c609d62a8c86-166833015581975.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/bc66e79cf2decf543a4c0de3902f257b-166833015581976.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/2abbb8cf38ef0b7bc71cb4ff85c61f1c-166833015581977.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/151a3202b0f470cfe608ee6cdc4f0e55-166833015581978.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/87d023f2b13c30f6f0248ee085d7f933-166833015581979.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/2d207c40d4ed4aad351b0574c350c05c-166833015581980.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/2232d584b1105c1c111a6d24dc4232bc-166833015581981.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/93f55c2f8dc74acbb1ea7606ee60f989-166833015581982.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/4cefb3a82b2456df50beb419a43bd04c-166833015581983.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/08d72b71dd46721eaa0f9158add23515-166833015581984.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/2485ee1c3461410a66d0c7eef09f5509-166833015581985.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/587119267467e85e47a9d50f2273e939-166833015581986.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/f52abfb2fbdea7ddf2b8763e5a182598-166833015581987.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/image-20221113170249308.png">
<meta property="article:published_time" content="2022-12-11T14:49:00.000Z">
<meta property="article:modified_time" content="2023-10-04T08:56:25.948Z">
<meta property="article:author" content="xiaoeryu">
<meta property="article:tag" content="x86内存管理">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://xiaoeeyu.github.io/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/62bfe0734f409c5d5c8112070c36e1c1-16683301558173.png">
    
    
    <!--- Icon Part-->
    <link rel="icon" type="image/png" href="/images/rabete.jpg" sizes="192x192">
    <link rel="apple-touch-icon" sizes="180x180" href="/images/rabete.jpg">
    <meta name="theme-color" content="#A31F34">
    <link rel="shortcut icon" href="/images/rabete.jpg">
    <!--- Page Info-->
    
    <title>
        
            分页和动态页面分配 | xiaoeryu
        
    </title>

    
<link rel="stylesheet" href="/fonts/Chillax/chillax.css">


    <!--- Inject Part-->
    

    
<link rel="stylesheet" href="/css/style.css">


    
        
<link rel="stylesheet" href="/css/build/tailwind.css">

    

    
<link rel="stylesheet" href="/fonts/GeistMono/geist-mono.css">

    
<link rel="stylesheet" href="/fonts/Geist/geist.css">

    <!--- Font Part-->
    
    
    
    
    
    

    <script id="hexo-configurations">
    window.config = {"hostname":"xiaoeeyu.github.io","root":"/","language":"zh-CN","path":"search.xml"};
    window.theme = {"articles":{"style":{"font_size":"16px","line_height":1.5,"image_border_radius":"14px","image_alignment":"center","image_caption":false,"link_icon":true,"delete_mask":false,"title_alignment":"left","headings_top_spacing":{"h1":"3.2rem","h2":"2.4rem","h3":"1.9rem","h4":"1.6rem","h5":"1.4rem","h6":"1.3rem"}},"word_count":{"enable":true,"count":true,"min2read":true},"author_label":{"enable":true,"auto":false,"list":[]},"code_block":{"copy":true,"style":"mac","highlight_theme":{"light":"github","dark":"vs2015"},"font":{"enable":false,"family":null,"url":null}},"toc":{"enable":true,"max_depth":4,"number":false,"expand":true,"init_open":true},"copyright":{"enable":true,"default":"cc_by_nc_sa"},"lazyload":true,"pangu_js":false,"recommendation":{"enable":false,"title":"推荐阅读","limit":3,"mobile_limit":2,"placeholder":"/images/ball-0101.jpg","skip_dirs":[]}},"colors":{"primary":"#A31F34","secondary":null,"default_mode":"light"},"global":{"fonts":{"chinese":{"enable":false,"family":null,"url":null},"english":{"enable":false,"family":null,"url":null},"title":{"enable":false,"family":null,"url":null}},"content_max_width":"1000px","sidebar_width":"210px","hover":{"shadow":true,"scale":false},"scroll_progress":{"bar":false,"percentage":true},"website_counter":{"url":"https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js","enable":true,"site_pv":true,"site_uv":true,"post_pv":true},"single_page":true,"preloader":{"enable":false,"custom_message":null},"open_graph":true,"google_analytics":{"enable":false,"id":null}},"home_banner":{"enable":true,"style":"fixed","image":{"light":"/images/wallhaven-jxl31y.png","dark":"/images/wallhaven-o5762l.png"},"title":"XIAOERYU","subtitle":{"text":["明心见性，拨云见日","Don't wait, to create"],"hitokoto":{"enable":false,"show_author":false,"api":"https://v1.hitokoto.cn"},"typing_speed":100,"backing_speed":80,"starting_delay":500,"backing_delay":1500,"loop":true,"smart_backspace":true},"text_color":{"light":"#fff","dark":"#d1d1b6"},"text_style":{"title_size":"2.8rem","subtitle_size":"1.5rem","line_height":1.2},"custom_font":{"enable":false,"family":null,"url":null},"social_links":{"enable":true,"style":"default","links":{"github":"https://github.com/xiaoeeyu","instagram":null,"zhihu":null,"twitter":null,"email":"xiaoeryu@163.com"},"qrs":{"weixin":null}}},"plugins":{"feed":{"enable":false},"aplayer":{"enable":false,"type":"fixed","audios":[{"name":null,"artist":null,"url":null,"cover":null,"lrc":null}]},"mermaid":{"enable":false,"version":"9.3.0"}},"version":"2.8.2","navbar":{"auto_hide":false,"color":{"left":"#f78736","right":"#367df7","transparency":35},"width":{"home":"1200px","pages":"1000px"},"links":{"Home":{"path":"/","icon":"fa-regular fa-house"},"Archives":{"path":"/archives","icon":"fa-regular fa-archive"}},"search":{"enable":true,"preload":true}},"page_templates":{"friends_column":2,"tags_style":"blur"},"home":{"sidebar":{"enable":true,"position":"left","first_item":"menu","announcement":null,"show_on_mobile":true,"links":null},"article_date_format":"auto","excerpt_length":200,"categories":{"enable":true,"limit":3},"tags":{"enable":true,"limit":3}},"footerStart":"2022/8/17 11:45:14"};
    window.lang_ago = {"second":"%s 秒前","minute":"%s 分钟前","hour":"%s 小时前","day":"%s 天前","week":"%s 周前","month":"%s 个月前","year":"%s 年前"};
    window.data = {"masonry":false};
  </script>
    
    <!--- Fontawesome Part-->
    
<link rel="stylesheet" href="/fontawesome/fontawesome.min.css">

    
<link rel="stylesheet" href="/fontawesome/brands.min.css">

    
<link rel="stylesheet" href="/fontawesome/solid.min.css">

    
<link rel="stylesheet" href="/fontawesome/regular.min.css">

    
    
    
    
<meta name="generator" content="Hexo 6.3.0">
<style>.github-emoji { position: relative; display: inline-block; width: 1.2em; min-height: 1.2em; overflow: hidden; vertical-align: top; color: transparent; }  .github-emoji > span { position: relative; z-index: 10; }  .github-emoji img, .github-emoji .fancybox { margin: 0 !important; padding: 0 !important; border: none !important; outline: none !important; text-decoration: none !important; user-select: none !important; cursor: auto !important; }  .github-emoji img { height: 1.2em !important; width: 1.2em !important; position: absolute !important; left: 50% !important; top: 50% !important; transform: translate(-50%, -50%) !important; user-select: none !important; cursor: auto !important; } .github-emoji-fallback { color: inherit; } .github-emoji-fallback img { opacity: 0 !important; }</style>
</head>



<body>
	<div class="progress-bar-container">
	

	
	<span class="pjax-progress-bar"></span>
	<!--        <span class="swup-progress-icon">-->
	<!--            <i class="fa-solid fa-circle-notch fa-spin"></i>-->
	<!--        </span>-->
	
</div>

<main class="page-container" id="swup">

	

	<div class="main-content-container flex flex-col justify-between min-h-dvh">
		<div class="main-content-header">
			<header class="navbar-container px-6 md:px-12">
    <div class="navbar-content transition-navbar ">
        <div class="left">
            
                <a class="logo-image h-8 w-8 sm:w-10 sm:h-10 mr-3" href="/">
                    <img src="/images/rabete.jpg" class="w-full h-full rounded-sm">
                </a>
            
            <a class="logo-title" href="/">
                
                xiaoeryu
                
            </a>
        </div>

        <div class="right">
            <!-- PC -->
            <div class="desktop">
                <ul class="navbar-list">
                    
                        
                            

                            <li class="navbar-item">
                                <!-- Menu -->
                                <a class=""
                                   href="/"
                                        >
                                    <i class="fa-regular fa-house fa-fw"></i>
                                    首页
                                    
                                </a>

                                <!-- Submenu -->
                                
                            </li>
                    
                        
                            

                            <li class="navbar-item">
                                <!-- Menu -->
                                <a class=""
                                   href="/archives"
                                        >
                                    <i class="fa-regular fa-archive fa-fw"></i>
                                    归档
                                    
                                </a>

                                <!-- Submenu -->
                                
                            </li>
                    
                    
                        <li class="navbar-item search search-popup-trigger">
                            <i class="fa-solid fa-magnifying-glass"></i>
                        </li>
                    
                </ul>
            </div>
            <!-- Mobile -->
            <div class="mobile">
                
                    <div class="icon-item search search-popup-trigger"><i class="fa-solid fa-magnifying-glass"></i>
                    </div>
                
                <div class="icon-item navbar-bar">
                    <div class="navbar-bar-middle"></div>
                </div>
            </div>
        </div>
    </div>

    <!-- Mobile sheet -->
    <div class="navbar-drawer h-dvh w-full absolute top-0 left-0 bg-background-color flex flex-col justify-between">
        <ul class="drawer-navbar-list flex flex-col px-4 justify-center items-start">
            
                
                    

                    <li class="drawer-navbar-item text-base my-1.5 flex flex-col w-full">
                        
                        <a class="py-1.5 px-2 flex flex-row items-center justify-between gap-1 hover:!text-primary active:!text-primary text-2xl font-semibold group border-b border-border-color hover:border-primary w-full "
                           href="/"
                        >
                            <span>
                                首页
                            </span>
                            
                                <i class="fa-regular fa-house fa-sm fa-fw"></i>
                            
                        </a>
                        

                        
                    </li>
            
                
                    

                    <li class="drawer-navbar-item text-base my-1.5 flex flex-col w-full">
                        
                        <a class="py-1.5 px-2 flex flex-row items-center justify-between gap-1 hover:!text-primary active:!text-primary text-2xl font-semibold group border-b border-border-color hover:border-primary w-full "
                           href="/archives"
                        >
                            <span>
                                归档
                            </span>
                            
                                <i class="fa-regular fa-archive fa-sm fa-fw"></i>
                            
                        </a>
                        

                        
                    </li>
            

            
            
        </ul>

        <div class="statistics flex justify-around my-2.5">
    <a class="item tag-count-item flex flex-col justify-center items-center w-20" href="/tags">
        <div class="number text-2xl sm:text-xl text-second-text-color font-semibold">92</div>
        <div class="label text-third-text-color text-sm">标签</div>
    </a>
    <a class="item tag-count-item flex flex-col justify-center items-center w-20" href="/categories">
        <div class="number text-2xl sm:text-xl text-second-text-color font-semibold">14</div>
        <div class="label text-third-text-color text-sm">分类</div>
    </a>
    <a class="item tag-count-item flex flex-col justify-center items-center w-20" href="/archives">
        <div class="number text-2xl sm:text-xl text-second-text-color font-semibold">112</div>
        <div class="label text-third-text-color text-sm">文章</div>
    </a>
</div>
    </div>

    <div class="window-mask"></div>

</header>


		</div>

		<div class="main-content-body transition-fade-up">
			

			<div class="main-content">
				<div class="post-page-container flex relative justify-between box-border w-full h-full">
	<div class="article-content-container">

		<div class="article-title relative w-full">
			
			<div class="w-full flex items-center pt-6 justify-start">
				<h1 class="article-title-regular text-second-text-color tracking-tight text-4xl md:text-6xl font-semibold px-2 sm:px-6 md:px-8 py-3">分页和动态页面分配</h1>
			</div>
			
		</div>

		
		<div class="article-header flex flex-row gap-2 items-center px-2 sm:px-6 md:px-8">
			<div class="avatar w-[46px] h-[46px] flex-shrink-0 rounded-medium border border-border-color p-[1px]">
				<img src="/images/rabete.jpg">
			</div>
			<div class="info flex flex-col justify-between">
				<div class="author flex items-center">
					<span class="name text-default-text-color text-lg font-semibold">xiaoeryu</span>
					
					<span class="author-label ml-1.5 text-xs px-2 py-0.5 rounded-small text-third-text-color border border-shadow-color-1">Lv5</span>
					
				</div>
				<div class="meta-info">
					<div class="article-meta-info">
    <span class="article-date article-meta-item">
        <i class="fa-regular fa-pen-fancy"></i>&nbsp;
        <span class="desktop">2022-12-11 22:49</span>
        <span class="mobile">2022-12-11 22:49</span>
        <span class="hover-info">创建</span>
    </span>
    
        <span class="article-date article-meta-item">
            <i class="fa-regular fa-wrench"></i>&nbsp;
            <span class="desktop">2023-10-04 16:56:25</span>
            <span class="mobile">2023-10-04 16:56:25</span>
            <span class="hover-info">更新</span>
        </span>
    

    
        <span class="article-categories article-meta-item">
            <i class="fa-regular fa-folders"></i>&nbsp;
            <ul>
                
                
                    
                        
                        <li>
                            <a href="/categories/X86%E6%B1%87%E7%BC%96%EF%BC%9A%E5%AE%9E%E6%A8%A1%E5%BC%8F%E5%88%B0%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F/">X86汇编：实模式到保护模式</a>&nbsp;
                        </li>
                    
                    
                
            </ul>
        </span>
    
    
        <span class="article-tags article-meta-item">
            <i class="fa-regular fa-tags"></i>&nbsp;
            <ul>
                
                    <li>
                        <a href="/tags/x86%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/">x86内存管理</a>&nbsp;
                    </li>
                
            </ul>
        </span>
    

    
    
    
    
        <span class="article-pv article-meta-item">
            <i class="fa-regular fa-eye"></i>&nbsp;<span id="busuanzi_value_page_pv"></span>
        </span>
    
</div>

				</div>
			</div>
		</div>
		

		


		<div class="article-content markdown-body px-2 sm:px-6 md:px-8 pb-8">
			<h2 id="01-保护模式下的段式虚拟内存管理"><a href="#01-保护模式下的段式虚拟内存管理" class="headerlink" title="01. 保护模式下的段式虚拟内存管理"></a>01. 保护模式下的段式虚拟内存管理</h2><span id="more"></span>

<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/62bfe0734f409c5d5c8112070c36e1c1-16683301558173.png" class="">
<p>任务的划分实际上是内存空间的划分</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/036caff772c8fd8009a012aaf154b714-16683301558161.png" class="">
<p>内存空间的访问时依靠分段机制进行的，是通过将内存划分为段来进行的。现在描述符表中定义每个段的描述符，然后通过描述符来访问其对应的内存段。</p>
<p>程序中先将段选择子送入段寄存器<strong>sreg</strong>中，再使用<mark>jmp、call</mark>指令进行跳转。其中段选择子的<strong>TI = 0</strong>表示描述符再GDT中，<strong>TI = 1</strong>表示在LDT中。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/fe2e91264c510777c1f5ab83f4ed81e3-16683301558172.png" class="">
<p>每个任务的描述符索引是13位，最多<strong>2^13 = 8192</strong>个，段内偏移是32位的，段的最大长度是<strong>2^32 = 4GB</strong>，则任务的全局部分为<strong>2^13 * 2^32 = 2^45 = 32TB</strong>，任务的私有部分为<strong>2^13 * 2^32 = 2^45 = 32TB</strong>，则一个任务的理论总大小为<strong>64TB</strong>。在一个多任务系统中，还有其他多个任务。但是32跟地址线最多能寻址4GB的物理内存空间。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/3a4cfb5324b487b51a585fe54fc56503-16683301558174.png" class="">
<p>上图中，任务的全局部分占用物理内存的高2G字节，任务的私有部分占用物理内存的低2G字节</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/bb0b37403a3132f2c94521f606306756-16683301558175.png" class="">
<p>开始将所有段的<strong>P位</strong>清零，表示暂时不在内存中，把要访问的段<strong>P位置1</strong>，将其调入物理内存中</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/7926fbcef13874a2671f401b9a37b35f-16683301558176.png" class="">
<p>将段1置换到外部磁盘、将段1的<strong>P位</strong>清零、将段3置换到物理内存、将段3的<strong>P位</strong>置1</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/584e40306c3dc5a8a811fe0e018ba3d2-16683301558178.png" class="">
<p>下次访问段1，发现<strong>P = 0</strong>，首先将其置换到物理内存中、再将段3的<strong>P位</strong>清零、再将段1的<strong>P位</strong>置1.使用上述这种方式实现<strong>段式虚拟内存管理策略</strong>。</p>
<p>实际中，段有大有小当内存空间不足时需要进行段的换入换出，置换出当前使用最少的段。在描述符中有一个特殊的<strong>位A</strong>，表示以访问位。当处理器访问一个段时，自动将<strong>A</strong>置1，根据<strong>A位</strong>被改变的频次可以知道哪些段是是用最少的，就能对其进行置换。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/34904d9c5835832a2e72d6ea283c84ff-16683301558177.png" class="">
<p>如上图，由于段的长度不同，在进行段的换入换出之后，虽然内存中剩余容量足够，但是内存不连续，也导致不能被使用。就如<strong>段5</strong>无法被调入内存。<strong>x86</strong>使用了内存分页技术解决这个问题，将物理内存分为大小相同的页，并将长度不同的段映射近长度相同的页。</p>
<h2 id="02-每个任务独立的虚拟内存"><a href="#02-每个任务独立的虚拟内存" class="headerlink" title="02. 每个任务独立的虚拟内存"></a>02. 每个任务独立的虚拟内存</h2><p>每个任务都分配一个4GB的虚拟内存空间低一半<mark>0x00000000 ~ 0x7FFFFFFF</mark>为私有部分，高一半<mark>0x80000000 ~ 0xFFFFFFFF</mark>为全局部分。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/d47a393d2fdb43c0a19a9c42d2c3e708-16683301558179.png" class="">
<p>在多任务系统中，任务的全局部分共有，私有部分独立：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/c75045c9e153d106f0ee9c46e78b4d21-166833015581710.png" class="">
<p>重新规划任务的内存空间：全局部分和私有部分各有2GB，如下，若私有部分有5个段，分别映射到2GB字节虚拟内存中。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/6bbc331d521c2b23008955260caf01da-166833015581712.png" class="">


<h2 id="03-物理内存的分页以及段到页的拆分"><a href="#03-物理内存的分页以及段到页的拆分" class="headerlink" title="03. 物理内存的分页以及段到页的拆分"></a>03. 物理内存的分页以及段到页的拆分</h2><p>任务对应为一些文件，最主要的可执行文件包含代码段、数据段、栈段以及段的实际内容，其他文件可以是工作文档、图像、视频文件等等，可以被加载到数据段中进行处理。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/93616ac55c672e94aecb012e18395328-166833015581713.png" class="">
<p>内核有自己的可执行文件和其它文件，是所有任务共享的，每个任务都有自己的可执行文件和其他文件。</p>
<p>当任务执行时，要把可执行文件都映射到自己的虚拟内存，映射就是计算每个段在虚拟内存中的起始位置和长度，然后创建和安装其描述符。</p>
<p>映射之后，下一步工作是将段进行切分，然后加载到物理内存。物理内存是4G字节，每一部分都是一个页，页的最小长度是4KB。之后就是将虚拟内存中的段进行4K字节的拆分映射到物理内存中</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/36a2e0300007314f584d45006d3de7ad-166833015581711.png" class="">
<p>如上图，在虚拟内存中的12606字节的段被划分到占3个4096字节完整的页 + 1个占318字节的页中。即使不足4KB也要按照4KB进行映射</p>
<p>段是连续的，页不需要是连续的。在内存中闲置的页和被占用的页是随机交错存在的，无法保证哪些页被释放哪些页被占用。也就无法保证分配的页在什么位置</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/5287f633388a52beac4c4258391c5a66-166833015581715.png" class="">
<p>对内存的分页是逻辑上的、而不是物理上的。同时页的起始位置也有要求，对于4KB的页来说，起始位置必须是4096字节（即0x1000)的整倍数。</p>
<p>课后练习题：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/885d06e0f92aa2df15899b4f9094e35a-166833015581714.png" class="">

<h2 id="04-处理器的段部件和页部件"><a href="#04-处理器的段部件和页部件" class="headerlink" title="04. 处理器的段部件和页部件"></a>04. 处理器的段部件和页部件</h2><p>分页（paing：名词，表示以页为基础的内存管理模式），开启分页机制后，在程序执行前，要把可执行文件中的段映射到虚拟内存，然后再把段中的内容加载到物理内存中的页。</p>
<p>为什么要引入虚拟内存、要把程序映射到虚拟内存呢？<br>Intel处理器是按照分段机制工作的，只不过在分页模式下，段是安排在虚拟内存的。将程序映射到虚拟内存就是规划所有段在虚拟内存中的布局和位置。并根据这些信息来创建段描述符</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/340687599ee7c41b66cadb4e85366328-166833015581717.png" class="">
<p>如上图，处理器只是规划可执行文件在虚拟内存中的布局，并不会把代码加载进虚拟内存中。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/ccb29b4b220f40bfa03a583e0251bfd4-166833015581716.png" class="">
<p>在没有开启分页机制时，段部件输出的地址就是物理地址</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/93b5bdef561fe3821708a0f77fa511f9-166833015581718.png" class="">
<p>开启分页机制后，段部件输出的地址就是线性地址，线性地址是虚拟内存中的地址，要传送给页部件，页部件用来将线性地址转换为物理地址</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/b1f267f0104a6773190214d35953bd65-166833015581719.png" class="">
<p><strong>页部件</strong>将<strong>段部件</strong>传送来的<strong>线性地址</strong>转换为<strong>物理地址</strong>。<strong>页部件</strong>将<strong>线性地址</strong>拆分成<strong>页地址</strong>和<strong>页内偏移</strong>，再将<strong>页地址</strong>修改为<strong>真实的物理页地址</strong>即可。如线性地址<strong>0x00201000</strong>，页部件将页地址转换为<strong>0x00004000</strong>、偏移为<strong>0xCC</strong>，则转换后的地址就是<strong>0x000040CC</strong>。</p>
<h2 id="05-从线性地址到物理地址的转换过程"><a href="#05-从线性地址到物理地址的转换过程" class="headerlink" title="05. 从线性地址到物理地址的转换过程"></a>05. 从线性地址到物理地址的转换过程</h2><p>线性地址到物理地址的转换：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/0b3f8e4539156e697b30c8330722dcef-166833015581721.png" class="">
<p><strong>线性地址的前20位</strong>对应<strong>物理地址的前20位</strong>。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/079466d3ffa8514574fe5a7827cc4ff0-166833015581722.png" class="">
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/b771000981bd8fddea1731849f08ee2a-166833015581720.png" class="">
<p>每个表项占4个字节，所以访问表项时，使用虚拟页地址的<strong>高20位</strong>乘以4</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/4defd07ca51dd0f680870b47b4bd5557-166833015581724.png" class="">

<ul>
<li>段描述符的基地址 + 指令中的偏移量传送给段部件</li>
<li>段部件输出线性地址<strong>0x0020010C8</strong></li>
<li>线性地址的<strong>高20</strong>位<strong>乘以4</strong>去访问表项取出物理页地址的<strong>高20位</strong></li>
<li>线性地址的<strong>低12位</strong>和上一步取出物理页地址的<strong>高20位</strong>结合形成物理地址</li>
<li>使用这个物理地址访问内存<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/6c560a13f33c3a4ab7c0e856e07fce62-166833015581723.png" class="">
各个任务都有自己独立的4GB虚拟内存空间和独立的页映射表。</li>
</ul>
<p>课后作业：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/a89f73cb347d517ecd51ad35d5df478d-166833015581725.png" class="">


<h2 id="06-页目录和页表及其地址转换过程"><a href="#06-页目录和页表及其地址转换过程" class="headerlink" title="06. 页目录和页表及其地址转换过程"></a>06. 页目录和页表及其地址转换过程</h2><img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/beb5acd012b007f792699b63338eff0f-166833015581727.png" class="">
<p>页映射表需要<strong>4MB</strong>大小</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/763bc09ba5fc0f5dd61cd15b5c4af155-166833015581726.png" class="">
<p>页映射表必须一开始就完全定义，而且会占用<strong>4MB</strong>内存空间。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/fcf277bc282630c1024cc9525453f59f-166833015581829.png" class="">
<p>层次化的分页结构，即不采用单一的<strong>页映射表</strong>，使用<strong>页目录表</strong>和<strong>页表</strong>替代。<br><strong>页表</strong>中每个<strong>页表项</strong>占据4个字节（32位）用来存放<strong>物理页地址</strong>，共可保存1024个<strong>物理页地址</strong>，即每个<strong>页表</strong>大小为4KB。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/c7312b043bc27fce971c77a8debceca8-166833015581831.png" class="">
<p><strong>CR3</strong>存放当前任务<strong>页目录</strong>的物理地址，也叫做<strong>页目录基址寄存器</strong></p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/92e225986b4e3925e3d7e7642af46952-166833015581828.png" class="">
<p>没有开启分页机制时，段部件发出的地址就是物理地址<strong>0x00801050</strong><br>开启分页机制：</p>
<ul>
<li>段部件发出线性地址，处理器将其分为三部分（高10位、中间10位、低12位）</li>
<li>处理器从当前任务状态段<strong>TSS</strong>中取出<strong>CR3</strong>寄存器的值，里面存放的是当前任务所用的页目录物理基地址</li>
<li>接着将线性地址高10位乘以4得到页目录中的偏移，从页目录的这个地址中取出页表的物理基地址</li>
<li>接着将线性地址的中间10位乘以4得到其在页表中的偏移，从页表的这个地址中取出线性地址对应的物理基地址</li>
<li>接着使用这个基地址<strong>加上</strong>线性地址的低12位形成物理地址，这样就把段部件发出的线性地址转换为<strong>物理地址了</strong></li>
</ul>
<p><strong>其中乘以4时因为页目录和页表中每一项都是占据4个字节的，所以需要乘以4才能得到每一项在表中对应的偏移</strong>。</p>
<p>这种变化是事先安排好的，当程序加载时操作系统先创建虚拟的段，根据段地址的高20位来判断需要用到哪些页目录项和页表项，之后在物理内存中寻找空闲的页，并将页的物理地址填写到对应的页表项中，之后程序就可以按照这些值把线性地址转换为物理地址。</p>
<h2 id="07-设计内核的页目录和页表"><a href="#07-设计内核的页目录和页表" class="headerlink" title="07. 设计内核的页目录和页表"></a>07. 设计内核的页目录和页表</h2><p>本章程序：<br>引导程序：<strong>c13_mbr0.asm</strong><br>内核程序：<strong>c31_core0.asm</strong><br>用户程序1：<strong>c30_app0.asm</strong><br>用户程序2：<strong>c30_app1.asm</strong></p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/419baf206d393622a45a6df21ff7a1db-166833015581830.png" class="">
<p>系统中的执行顺序为：</p>
<ul>
<li>先创建页目录和页表、在虚拟内存中规划每个段的位置并创建段描述符</li>
<li>处理器的页部件从段部件输出的线性地址中提取前20位作为索引来访问页目录表和页表，看对应的物理页是否存在</li>
<li>如果页不存在，则在物理内存中搜索这个物理页，并将页的物理地址填写在页表中，这样就可以访问这个物理页</li>
<li>如果页存在，则直接访问这个页找到对应的物理地址以此访问这个页</li>
</ul>
<p>内核程序中，显示处理器品牌信息之后开始准备打开分页机制。但是此时内核是都开启页功能之前加载的，其内容在内存中的位置已经固定。此时要想当前执行流程在开启分页之后还能继续进行，就必须让段部件发出的线性地址等于页部件发出的物理地址</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/f045a9fa5ce5ccbb02648df2229d15a8-166833015581832.png" class="">
<p>我们内核处于低端1MB，对低端1MB的内存特殊处理，让这部分的线性地址等于页部件转换之后的物理地址即可。那么这样做之后内核就不需要做任何变动就可以在分页机制下正常工作</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/234c965b022ff7b6681224e3a0062c63-166833015581833.png" class="">
<p>一个页表可以管理4MB内存，那么对于这个内核只需要一个页表即可。页目录和页表放在任何有效的物理内存地址都可，如上，放在<strong>0x00020000</strong>处。</p>
<h2 id="08-页目录项和页表项的组成格式"><a href="#08-页目录项和页表项的组成格式" class="headerlink" title="08. 页目录项和页表项的组成格式"></a>08. 页目录项和页表项的组成格式</h2><p>目的对于低端<strong>1MB</strong>内存，<strong>段部件发出的线性地址</strong>和<strong>页部件发出的物理地址</strong>相同。</p>
<p>创建页目录，将其清零：</p>
<pre><code class="assembly">    ;创建系统内核的页目录表PDT
    mov ecx,1024                       	;1024个目录项
    mov ebx,0x00020000                  ;页目录的物理地址
    xor esi,esi							;页目录表清零
.b1:
    mov dword [es:ebx+esi],0x00000000  	;页目录表项清零
    add esi,4
    loop .b1
</code></pre>
<p>页目录项、页表项的组成格式：在页目录中只保存了<mark>页<strong>表</strong>物理地址的高20位</mark>、在页表中只保存了<mark>页物理地址的高20位</mark>。因为页表和页目录要求是4K字节对齐，所以低12位为0</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/014976f410021c0c1e7c7413cd1827fb-166833015581836.png" class="">

<ul>
<li><strong>P位（Present）</strong>：1表示页表或页目录存在于内存中、0表示不在内存中，需要创建或从磁盘调入</li>
<li><strong>R/W位（Read/Write）</strong>：0页目录或页表只读、1表示可读可写</li>
<li><strong>US位（User/Supervisor）</strong>：1时表示所有特权级别的程序访问，0表示只有特权级0、1、2特权级的程序可以访问</li>
<li><strong>PWT位（Page Level Write-Through）</strong>：页级通写位，和高速缓存有关、通写是高速缓存的一种方式，0表示不允许使用此种方式提升页面访问效率、1表示允许</li>
<li><strong>PCD位（Page-Level Cache Disable）</strong>：高速缓存禁止位，0表示不使用高速缓存策略、1表示使用</li>
<li><strong>A位（Accessed）</strong>：由处理器固件设置，0表示此页未被访问过，1表示被访问过，操作系统定期将此位清零，通过此位被置1的次数了解此页的使用频率</li>
<li><strong>D位（Dirty）</strong>：由处理器固件设置，用来指示此表项的页已经写过数据。</li>
<li><strong>PAT位（Page-Attribute Table）</strong>：页属性表支持位，只对页表项起作用，页目录项中此位置0，和页高速缓存有关</li>
<li><strong>G位（Global）</strong>：指示该表项所指示的页是否为全局性质的，若页是全局的，他将会在高速缓存中一直保存，意味着地址转换的速度会很快</li>
<li><strong>AVL位（Available）</strong>：被处理器忽略，程序可以使用</li>
</ul>
<h2 id="09-创建内核的页表并初始化低端1MB对应的页表项"><a href="#09-创建内核的页表并初始化低端1MB对应的页表项" class="headerlink" title="09. 创建内核的页表并初始化低端1MB对应的页表项"></a>09. 创建内核的页表并初始化低端1MB对应的页表项</h2><p>在页目录内创建指向页目录自己的目录项：</p>
<pre><code class="assembly">    ;将页目录表的物理地址登记在它自己的最后一个页目录项内
    ;页目录也可以容纳1024个，从0到3FF，最后一项的偏移为3FF X 4 = 0xFFC = 4092
    mov dword [es:ebx+4092],0x00020003
</code></pre>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/e3c365f0007bf5d9b3833567346b3f4c-166833015581834.png" class="">
<p>程序前1MB占据一个页目录项和页表的前256个表项。修改页目录项的内容使其指向页表，填写的内容是页表的物理地址：<strong>0x00021000</strong>，该页位于内中，可读可写，但是不允许特权级别为3的程序访问，所以最终要填写<strong>0x00021003</strong>。</p>
<p>修改页目录中第一个表项的内容，使其指向页表：</p>
<pre><code class="assembly">    ;在页目录内创建与线性地址0x00000000对应的目录项
    mov dword [es:ebx+0],0x00021003    ;写入目录项（页表的物理地址和属性）
</code></pre>
<p>将低端1MB字节所包含的哪些页的物理地址按顺序填写到页表中：</p>
<pre><code class="assembly">    ;创建与上面那个目录项相对应的页表，初始化页表项
    mov ebx,0x00021000                 ;页表的物理地址
    xor eax,eax                        ;起始页的物理地址
    xor esi,esi
.b2:
    mov edx,eax
    or edx,0x00000003
    mov [es:ebx+esi*4],edx             ;登记页的物理地址
    add eax,0x1000                     ;下一个相邻页的物理地址
    inc esi
    cmp esi,256                        ;仅低端1MB内存对应的页才是有效的
    jl .b2
.b3:                                   ;其余的页表项置为无效
    mov dword [es:ebx+esi*4],0x00000000
    inc esi
    cmp esi,1024
    jl .b3
</code></pre>
<p>开启分页功能之后，页表和物理地址的映射关系：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/1cdef7a86047f1863b9f3ce7742d262d-166833015581835.png" class="">


<h2 id="10-设置控制寄存器CR3和CR0开启分页功能"><a href="#10-设置控制寄存器CR3和CR0开启分页功能" class="headerlink" title="10. 设置控制寄存器CR3和CR0开启分页功能"></a>10. 设置控制寄存器CR3和CR0开启分页功能</h2><p>开启分页：</p>
<pre><code class="assembly">    ;令CR3寄存器指向页目录，并正式开启页功能
    mov eax,0x00020000  ;PCD=PWT=0
    mov cr3,eax
    
    cli		;开启分页之前需要重新设置内核，不能发生中断，先关闭
    
    mov eax,cr0
    or eax,0x80000000
    mov cr0,eax			;开启分页机制
                        ;从这条指令开始，段部件产生的就是线性地址不是物理地址			
</code></pre>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/54d5c6a1dbf186708bbbdb66410eee24-166833015581837.png" class="">
<p>对控制寄存器使用MOV指令，和普通的MOV 指令不同，操作码不同</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/b1c16fc5f1bca227f50ff84a7bd875e7-166833015581839.png" class="">
<p><strong>CR0</strong>寄存器的<strong>位31</strong>，<strong>PG</strong>位，0表示关闭分页、1表示开启分页。<strong>CR0</strong>的<strong>位0</strong>，<strong>PE</strong>位，0表示位于实模式、1表示位于保护模式。分页只能在保护模式下开启</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/6ccae13d834791c7061285a74c59a792-166833015581838.png" class="">


<h2 id="11-在调试器中观察页目录表和页表"><a href="#11-在调试器中观察页目录表和页表" class="headerlink" title="11. 在调试器中观察页目录表和页表"></a>11. 在调试器中观察页目录表和页表</h2><p>写入程序：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/aecb11d2fe5887c73f36b8b825ac5b1b-166833015581840.png" class="">
<p>分页之前：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/6c70462626d0d82f01f81c56083debb5-166833015581842.png" class="">
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/9b4f60cf5f2e43889d5600832c6904b4-166833015581841.png" class="">
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/d098a012924babbbd497fd1eccabb229-166833015581843.png" class="">
<p>使用<strong>info tab</strong>命令查看可知，此时分页是关闭的。其中<strong>CR0</strong>的<strong>PG位</strong>是小写，为0。<strong>PE位</strong>大写为1，处于保护模式。</p>
<p>开启分页：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/67b42d52f153a06592223adf2b7f4d47-166833015581845.png" class="">
<p><strong>GDT</strong>内第二个描述符的线性地址为<strong>0x00007E08</strong></p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/0c417599ea065eef914819e2e1793415-166833015581844.png" class="">


<h2 id="12-准备将内核映射到虚拟内存的高端"><a href="#12-准备将内核映射到虚拟内存的高端" class="headerlink" title="12. 准备将内核映射到虚拟内存的高端"></a>12. 准备将内核映射到虚拟内存的高端</h2><p>页目录的<strong>高2G字节</strong>指向内核的页表、<strong>低2G字节</strong>指向任务的页表。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/acf80d1de43efe9f041004f4a3b904b0-166833015581846.png" class="">
<p>若页目录的<strong>高2GB</strong>不是指向内核的页表时，当从任务的私有部分转到内核执行时，段部件发出的地址一定是高于<strong>0x80000000</strong>的，此时就找不到内核所在的物理地址，无法完成地址转换。因此需要将内核映射到虚拟地址的高端</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/3ad1df59914bba12be726e1ae66c5926-166833015581847.png" class="">
<p>内核映射到虚拟地址高端之后的内存布局。内核是位于虚拟内存，现在只是让段部件发出的地址位于虚拟地址的高端。</p>
<h2 id="13-在分页机制下访问页目录表自身"><a href="#13-在分页机制下访问页目录表自身" class="headerlink" title="13. 在分页机制下访问页目录表自身"></a>13. 在分页机制下访问页目录表自身</h2><img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/9fc5d96dbc0a1504600ba8e77bb2b9b7-166833015581848.png" class="">
<p>上图，现在需要在页目录中添加一个表项，使其指向内核原先的位置</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/b6c561c38b70ea1b53dae22737bdfce1-166833015581849.png" class="">

<ul>
<li>页部件从<strong>CR3</strong>寄存器取出页部件的物理基地址，定位到页目录表</li>
<li>段部件发出的地址是<strong>0xFFFFF800</strong></li>
<li>取出<strong>高10位</strong>乘以4，作为页目录表内偏移，从页目录表中取出页表的物理地址，此时发现通过页目录表找到的页表仍然是页目录表自身的基址，即把页目录表当成页表使用</li>
<li>接着从线性地址<strong>中间10位</strong>取出页表内的偏移，取出页的物理基地址</li>
<li>再加上线性地址的<strong>低12位</strong>构成物理地址，去访问内存</li>
<li>将其设置为原先的值，这就将内核从虚拟内存的低端映射到了高端</li>
</ul>
<p>代码如下：</p>
<pre><code class="assembly">    ;在页目录内创建与线性地址0x80000000对应的目录项
    ;mov ebx,0xfffff000                 ;页目录自己的线性地址
    ;mov esi,0x80000000                 ;映射的起始地址
    ;shr esi,22                         ;线性地址的高10位是目录索引
    ;shl esi,2
    ;mov dword [es:ebx+esi],0x00021003  ;写入目录项（页表的物理地址和属性）
                             			;目标单元的线性地址为0xFFFFF200
    mov dword [es:0xfffff800], 0x00021003
</code></pre>
<h2 id="14-使内核在虚拟内存高端的映射生效"><a href="#14-使内核在虚拟内存高端的映射生效" class="headerlink" title="14. 使内核在虚拟内存高端的映射生效"></a>14. 使内核在虚拟内存高端的映射生效</h2><p>修改与内核有关的段描述符，以及<strong>GDT</strong>自己的线性地址</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/91a65c1fdf8d13e23c1bd7ec0059820a-166833015581850.png" class="">
<p>只需要修改内核所有段描述符的最高位，将其<strong>置1</strong>即可（等于加上0x80000000)，代码如下：</p>
<pre><code class="assembly">    ;将GDT中的段描述符映射到线性地址0x80000000
    sgdt [pgdt]
    
    mov ebx,[pgdt+2]
    
    or dword [es:ebx+0x10+4],0x80000000;处理保护模式下初始代码段描述符
    or dword [es:ebx+0x18+4],0x80000000;处理内核的栈段描述符
    or dword [es:ebx+0x20+4],0x80000000;处理显示缓冲区描述符
    or dword [es:ebx+0x28+4],0x80000000;处理公共例程段描述符
    or dword [es:ebx+0x30+4],0x80000000;处理内核数据段描述符
    or dword [es:ebx+0x38+4],0x80000000;处理内核代码段描述符
    
    add dword [pgdt+2],0x80000000      ;GDTR也用的是线性地址
    
    lgdt [pgdt]							;使得修改生效
</code></pre>
<p>修改中断描述符表<strong>IDTR</strong>，因为中断描述符表已经被映射到虚拟内存的高端</p>
<pre><code class="assembly">    ;修改IDTR，将中断描述符表映射到线性地址高端
    sidt [pidt]
    add dword [pidt+2],0x80000000      ;IDTR也用的是线性地址
    lidt [pidt]
</code></pre>
<p>段寄存器由段选择器和描述符高速缓存器组成，处理器执行指令时，不会每次都加载段选择器，而是使用段描述符高速缓存器中的基地址访问内存。</p>
<p>所以当修改了<strong>GDT</strong>的基地址或段描述符之后，这些修改不会立即反映到段描述符高速缓存器，对程序的运行没有任何影响。</p>
<p>但是当执行一个段间转移指令、或向段寄存器里加载一个新的段描述符选择子时，处理器会访问<strong>GDT</strong>或<strong>LDT</strong>，将刷新段寄存器的描述神高速缓存器中的内容</p>
<p>因此为了使处理器转移到内存高端执行，需要显示的刷新段寄存器内容，代码段<strong>CS</strong>的刷新需要用转移指令完成：</p>
<pre><code class="assembly">    jmp core_code_seg_sel:flush        ;刷新段寄存器CS，启用高端线性地址
    ;导致处理器使用新的段选择子core_code_seg_sel来访问GDT；
    ;从中取出修改后的代码段描述符，并加载到CS描述符高速缓存器中；
    ;这直接导致处理器从虚拟地址高端取指令执行
    
flush:
    mov eax,core_stack_seg_sel		;刷新SS，同时刷新其描述符高速缓存器
    mov ss,eax						;物理地址没有改变，改变的是线性地址
    
    mov eax,core_data_seg_sel		;刷新DS，同时刷新其描述符高速缓存器
    mov ds,eax						;物理地址没有改变，改变的是线性地址
</code></pre>
<p>即使是在分页机制下，显存的基地址部分加上了<strong>0x80000000</strong>，例程<strong>put_string</strong>和<strong>put_char</strong>也没有做任何修改。</p>
<p>尽管显存基地址已经映射到<strong>0x800B8000</strong>，但是向这个虚拟的地址写数据时，页部件将会把它转换为真实的显存位置<strong>0x000B8000</strong>.</p>
<h2 id="15-为内核任务创建任务控制块TCB"><a href="#15-为内核任务创建任务控制块TCB" class="headerlink" title="15. 为内核任务创建任务控制块TCB"></a>15. 为内核任务创建任务控制块TCB</h2><p>接上一节，为系统服务例程安装门描述符，没有修改，因为门描述符的创建只涉及目标代码段的选择以及例程在段内的偏移量，不受内存映射的影响。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/08ee83725bed57df523f887bad4feb86-166833015581851.png" class="">
<p>接下来创建内核任务，内核任务有自己的动态空间<strong>TCB</strong>，而且它的空间不是动态分配的，是明确指定的的。由于内核被映射到高端字节，所以内核<strong>TCB</strong>的线性地址也变为<strong>0x8001F800</strong>.代码如下：</p>
<pre><code class="assembly">    ;对门进行测试 
    mov ebx,message_2
    call far [salt_1+256]              ;通过门显示信息(偏移量将被忽略) 
    
    ;开始创建和确立内核任务
    mov ecx,core_lin_tcb_addr          ;移至高端之后的内核任务TCB线性地址
    mov word [es:ecx+0x04],0xffff      ;任务的状态为“忙”
    mov dword [es:ecx+0x46],core_lin_alloc_at
                                     ;登记内核中可用于分配的起始线性地址
    call append_to_tcb_link            ;将内核任务的TCB添加到TCB链中
    
    mov esi,ecx
</code></pre>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/a3b525b67a8d9b517437736e9ae5353f-166833015581852.png" class="">
<p>若之前分配过地址，在虚拟地址的低端<strong>1MB</strong>，之后就是建立虚拟地址和物理地址的映射；若要再分配内存，那就需要从<strong>0x100000</strong>开始分配，需要将上一个<strong>TCB</strong>的尾部结构修改为这次分配的地址起始位置，即<strong>0x100000</strong>。</p>
<h2 id="16-为内核任务的TSS分配内存空间"><a href="#16-为内核任务的TSS分配内存空间" class="headerlink" title="16. 为内核任务的TSS分配内存空间"></a>16. 为内核任务的TSS分配内存空间</h2><pre><code class="assembly">    ;为内核任务的TSS分配内存空间。所有TSS必须创建在内核空间
    mov ecx,104                        ;为该任务的TSS分配内存
    call sys_routine_seg_sel:allocate_memory	;创建TSS所需内存是动态分配的
                                                ;必须在内核的虚拟地址空间中
    mov [es:esi+0x14],ecx              ;在内核TCB中保存TSS基地址
</code></pre>
<p>例程<strong>allocate_memory</strong>：</p>
<pre><code class="assembly">allocate_memory:			;在当前任务的地址空间中分配内存
                     	 	;输入：ECX=希望分配的字节数
                      		;输出：ECX=起始线性地址 
    push eax
    push ebx
    
    push ds
    
    ;得到TCB链表首节点的线性地址
    ;因为是在当前任务的虚拟线性空间中分配，所以需要搜索TCB链表
    ;找到当前TCB，从中取得可用于分配的线性地址，从这个地址处开始分配
    mov eax,core_data_seg_sel
    mov ds,eax
    
    mov eax,[tcb_chain]                ;EAX=首节点的线性地址
    
    mov ebx,mem_0_4_gb_seg_sel
    mov ds,ebx
    
    ;搜索状态为忙（当前任务）的节点
.s0:
    cmp word [eax+0x04],0xffff
    jz .s1				;找到忙的节点，EAX=节点的线性地址
    mov eax,[eax]
    jmp .s0
    
    ;开始分配内存
.s1:
    mov ebx,eax			;找到忙的节点，EAX=节点的线性地址
    call sys_routine_seg_sel:task_alloc_memory
    
    pop ds
    
    pop ebx
    pop eax
    
    retf
</code></pre>
<p>其中例程<strong>task_alloc_memory</strong>：</p>
<pre><code class="assembly">task_alloc_memory:		;在指定任务的虚拟内存空间中分配内存
                        ;并不一定是在当前任务的虚拟内存空间中分配
          				;输入：EBX=任务控制块TCB的线性地址
          				;      ECX=希望分配的字节数
          				;输出：ECX=已分配的起始线性地址
    push eax
    
    push ds
    
    push ebx                           ;to A
    
    ;获得本次内存分配的起始线性地址
    mov ax,mem_0_4_gb_seg_sel
    mov ds,ax
    
    mov ebx,[ebx+0x46]                 ;获得本次分配的起始线性地址
    mov eax,ebx
    add ecx,ebx                        ;本次分配，最后一个字节之后的线性地址
    
    push ecx                           	;To B
                                        ;下一次可以分配的线性地址，需要压栈保护
    ;为请求的内存分配页
    and ebx,0xfffff000		;线性地址低12位没有用，将其清零
    and ecx,0xfffff000
.next:
    call sys_routine_seg_sel:alloc_inst_a_page
          								;安装当前线性地址所在的页
    add ebx,0x1000                     	;+4096
    cmp ebx,ecx
    jle .next
    
    ;将用于下一次分配的线性地址强制按4字节对齐
    pop ecx                            	;B
                                        ;原先保存下一次内存分配可以使用的起始线性地址
                                        ;弹出之后要保存到TCB中，这里要先对齐
    test ecx,0x00000003                ;线性地址是4字节对齐的吗？
    jz .algn                           ;是，直接返回
    add ecx,4                          ;否，强制按4字节对齐
    and ecx,0xfffffffc
    
.algn:
    pop ebx                            ;A
    
    mov [ebx+0x46],ecx                 ;将下次分配可用的线性地址回存到TCB中
    mov ecx,eax
    
    pop ds
    
    pop eax
    
    retf
</code></pre>
<h2 id="17-处理与线性地址对应的页目录项和页表项"><a href="#17-处理与线性地址对应的页目录项和页表项" class="headerlink" title="17. 处理与线性地址对应的页目录项和页表项"></a>17. 处理与线性地址对应的页目录项和页表项</h2><p>接上一节，知道本次内存分配涉及哪些线性地址，这是一个连续的线性地址范围区间，通过循环反复调用<strong>alloc_inst_a_page</strong>来安装与这些线性地址对应的物理页。</p>
<p>其中例程<strong>task_alloc_memory</strong>：</p>
<pre><code class="assembly">task_alloc_memory:
。。。
    ;为请求的内存分配页
    and ebx,0xfffff000		;线性地址低12位没有用，将其清零
    and ecx,0xfffff000
.next:
    call sys_routine_seg_sel:alloc_inst_a_page
          								;安装当前线性地址所在的页
    add ebx,0x1000                     	;+4096
    cmp ebx,ecx
    jle .next
</code></pre>
<p>其中例程<strong>alloc_inst_a_page</strong>用来为指定的线性地址分配一个物理页</p>
<pre><code class="assembly">    alloc_inst_a_page:	;分配一个页，并安装在当前活动的
                        ;层级分页结构中
                        ;输入：EBX=页的线性地址
    push eax
    push ebx
    push ecx
    push esi
    push ds
    
    mov eax,mem_0_4_gb_seg_sel
    mov ds,eax		;后面用线性地址访问页目录表和页表自身做准备
    
    ;线性地址的高10位是页目录表索引
    ;用它来检查该线性地址所对应的页表是否存在
    mov esi,ebx
    and esi,0xffc00000                 ;清除页表索引和页内偏移部分
    shr esi,20                         ;将页目录索引乘以4作为页内偏移
    or esi,0xfffff000                  ;页目录自身的线性地址+表内偏移
    
    test dword [esi],0x00000001        ;P位是否为“1”。检查该线性地址是
    jnz .b1                            ;否已经有对应的页表
    
    ;页目录项不存在，就创建一个新的页表，并将页表的地址写入这个页目录项
    ;创建并安装该线性地址所对应的页表
    call allocate_a_4k_page		;分配一个页做为页表
                                ;这个物理地址只保留前20位
                                ;后12位是页的属性值，为0x07
    or eax,0x00000007			;US位是1，即特权级3也可以访问
                                ;现在是在为内核人物的TSS分配内存
                                ;TSS只能由特权级0的内核任务访问，其所在的页也只能有
                                ;特权级0的内核任务访问，但是这里为什么允许特权级3的内存访问呢？
                                ;
                                ;原则上是不允许的，但是这个例程是通用的，3特权级要求US位是1，
                                ;0特权级要求US位是0，
                                ;为了省事就把US位置1了
    mov [esi],eax               ;在页目录中登记该页表,将页目录项的内容修改为页表的物理地址
    
    ;清空当前页表，把页表当成普通的页来用
    mov eax,ebx
    and eax,0xffc00000	;清空低22位
    shr eax,10			;右移10次
    or eax,0xffc00000	;将高10位设置成0x3FF
    mov ecx,1024		;之后用循环访问页表内的全部页表项
.cls0:
    mov dword [es:eax],0x00000000
    add eax,4			;加4得到下一个页表项
    loop .cls0
    
.b1:
    ;检查该线性地址对应的页表项（页）是否存在
    mov esi,ebx
    and esi,0xfffff000                 ;清除页内偏移部分
    shr esi,10                         ;将页目录索引变成页表索引，页表索引乘以4作为页内偏移
    or esi,0xffc00000                  ;得到该线性地址对应的页表项
    
    test dword [esi],0x00000001        ;P位是否为“1”。检查该线性地址是
    jnz .b2                            ;否已经有对应的页
    
    ;创建并安装该线性地址所对应的页
    call allocate_a_4k_page            ;分配一个页，这才是要安装的页
    or eax,0x00000007
    mov [esi],eax
    
.b2:
    pop ds
    pop esi
    pop ecx
    pop ebx
    pop eax
    
    retf
</code></pre>
<p>其中把页目录表当成页表使用：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/7b5c22e8ad8cf86185d4ec963a28e64a-166833015581853.png" class="">
<p>即页目录表的高10位右移到最右端，再左移两位补0，其余补1.这个线性地址就可以把页目录表当成一个页来用，即访问页目录表自身。</p>
<p>其中把页表当成普通的页来用：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/272b36f0833457b2c03537b9216d8e1f-166833015581854.png" class="">


<h2 id="18-根据需要分配物理页并设置页表项"><a href="#18-根据需要分配物理页并设置页表项" class="headerlink" title="18. 根据需要分配物理页并设置页表项"></a>18. 根据需要分配物理页并设置页表项</h2><p>接上一节，其中例程<strong>alloc_inst_a_page</strong>：用来为指定的线性地址分配一个物理页</p>
<pre><code class="assembly">alloc_inst_a_page:

    ......
    
      .b1:
         ;检查该线性地址对应的页表项（页）是否存在
         mov esi,ebx
         and esi,0xfffff000                 ;清除页内偏移部分
         shr esi,10                         ;将页目录索引变成页表索引，页表索引乘以4作为页内偏移
         or esi,0xffc00000                  ;得到该线性地址对应的页表项

         test dword [esi],0x00000001        ;P位是否为“1”。检查该线性地址是
         jnz .b2                            ;否已经有对应的页

         ;创建并安装该线性地址所对应的页
         call allocate_a_4k_page            ;分配一个页，这才是要安装的页
         or eax,0x00000007
         mov [esi],eax

  .b2:
         pop ds
         pop esi
         pop ecx
         pop ebx
         pop eax

         retf
                 
</code></pre>
<p>要想判断与线性地址对应的页表项是否有效，需要访问页表自身，将页表当成一个普通的页来访问。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/a05d401b9a96a903b54d20c9fb3d038a-166833015581855.png" class="">
<p>此时图中第三行的线性地址就是我们要访问的那个页表项的线性地址</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/0fd5c986eb285833f1dfcfffe044b0ac-166833015581856.png" class="">
<p>如上图，访问过程。</p>
<h2 id="19-物理内存的页面管理和页映射位串"><a href="#19-物理内存的页面管理和页映射位串" class="headerlink" title="19. 物理内存的页面管理和页映射位串"></a>19. 物理内存的页面管理和页映射位串</h2><p>无论分配页表还是物理页，都要调用例程<strong>allocate_a_4k_page</strong>，这个例程用来分配物理页，对于每个任务来说内存分配包括两个互相连续的部分：首先是在任务自己的虚拟内存空间中分配，然后将其映射到物理内存中的页。</p>
<p>物理页的数量是有限的，是所有任务共享的，若物理页空间不足，还需要执行内存换入换出操作。操作系统需要在上电之后就检测实际的物理内存数量，并建立一张表格登记每个页的基本信息，包括页的物理地址以及是否空闲。<strong>4GB</strong>共可分配<mark>1048576</mark>个页，为了简单起见，使用位串指定页的位置和分配情况。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/e66f60ea08bb0e11cc9de0dd2e497b7a-166833015581857.png" class="">
<p>比特的位置决定页的位置，比特位的值决定了页的分配情况，<strong>0</strong>表示此页空闲、<strong>1</strong>表示此页被占用。</p>
<p>在本章中没有检测实际内存的代码，仅仅假定我们只有<strong>2MB</strong>的物理内存空间可用，<strong>2MB = 512KB</strong>，需要<strong>512</strong>个位串，使用连续的字数据来声明位串，在内核数据段中：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/13f99b6ba093a2a18cba25f1489a24ab-166833015581858.png" class="">
<p>第一个字节<strong>0xff</strong>的<strong>位0</strong>对应<strong>物理地址为0</strong>的页，<strong>位1</strong>对应<strong>物理地址为0x1000</strong>的页；<br>第二个字节<strong>0xff</strong>的位0对应物理地址为<strong>0x8000</strong>的页，位1对应物理地址为<strong>0x9000</strong>的页；<br>把比特在比特串中的序号乘以<strong>0x1000</strong>就得到其所对应的物理页的地址（0x1000递增）。<br>前32字节对应内存最低端<strong>1MB</strong>中的页，共256个页。这一部分已经整体划归内核使用，没有被内核占用的部分也大多被外围硬件占用，包括ROM-BIOS。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/6a69e2857945ee2dba5b35e8cc22619f-166833015581859.png" class="">
<p>其中前32个字节中有两个<strong>0x55</strong>，对应<strong>48~63</strong>，16进制是<strong>0x30~0x3F</strong>，乘以<strong>0x1000</strong>之后对应物理页范围是<strong>0x30000~0x3F000</strong>共<strong>64KB</strong>，可以划分为16个页。为了表明页的分配是随机的，即连续的线性地址空间不必对应连续的页，有意将页在物理上分开，<strong>0x55 = 01010101</strong>，表示空闲页和已经分配的页是交替出现的。</p>
<p>但是将<strong>0x55</strong>对应的<strong>16个页</strong>作为空闲页分配未必合理，因为低端1MB内存已经分配给内核，在内核的页表中，已经有页表项指向这16个页，若在将其分配给其他任务，那么其他任务的页表项有势必指向这16个页，即重复分配。但是线性地址到物理页的映射可以是重复的，内核也不会使用这16个页，分配给其他任务也无妨。</p>
<h2 id="20-空闲页的搜索和BTS指令"><a href="#20-空闲页的搜索和BTS指令" class="headerlink" title="20. 空闲页的搜索和BTS指令"></a>20. 空闲页的搜索和BTS指令</h2><p>接上一节，查看例程<strong>allocate_a_4k_page</strong>：</p>
<pre><code class="assembly">    allocate_a_4k_page:			;分配一个4KB的页
                                ;输入：无
                                ;输出：EAX=页的物理地址
                                ;每个页的状态可以从页映射位串中获得
    push ebx
    push ecx
    push edx
    push ds
    
    mov eax,core_data_seg_sel
    mov ds,eax		;指向内核数据段，以便指向页映射位串
    
    xor eax,eax		;循环，从头开始搜索位串，查找空闲的页
                    ;从页映射位串中找到第一个为0的比特
                    ;记下在整个位串中的位置
.b1:
    bts [page_bit_map],eax	;搜索位串，寻找第一个为0的比特
    jnc .b2
    inc eax
    cmp eax,page_map_len*8
    jl .b1
    
    mov ebx,message_3
    call sys_routine_seg_sel:put_string
    hlt					;没有可以分配的页，停机
    
.b2:
    shl eax,12			;乘以4096（0x1000）
    
    pop ds
    pop edx
    pop ecx
    pop ebx
    
    ret
</code></pre>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/656dfa078ff57ba75bd187ffe33d9b41-166833015581860.png" class="">

<ul>
<li>测试位串中的某个比特，用该比特的值设置标志寄存器的进位标志<strong>CF</strong>，然后将位串中的比特置1</li>
<li>目的操作数：<strong>16、32、64</strong>位的通用寄存器，或者是用于指定位串起始位置的内存地址，若是寄存器，则指定的位串就是该寄存器的内容</li>
<li>源操作数：<strong>16、32、64</strong>位的通用寄存器，用于指定待测试比特在位串中的位置，索引</li>
<li>目的操作数和源操作数若都为通用寄存器，则长度必须是一致的</li>
</ul>
<p>目的操作数是通用寄存器：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/3dcec8f0d43ee50f8db16c63509ea2dc-166833015581861.png" class="">
<p><strong>EDX</strong>是<font color="red">待测试位串</font>，<strong>ECX</strong>包含那个待测试比特的索引。如果目的操作数是寄存器，<mark>则根据目的操作数的长度，处理器先求得源操作数除以<strong>16、32、64</strong>的余数，并将其作为待测试比特的索引<mark>，然后从<font color="red">待测试位串</font>中取得该比特，并传送到标志寄存器的<strong>CF</strong>位，最后将该比特<strong>置1</strong>。<br><mark>在这里就是将ecx除以32取余，将余数作为索引在edx中找到对应的比特位查看是0还是1，并将其写入EFLAGS的CF位，然后不管是0还是1都要将在edx中找到的对应比特位置1<mark>。</mark></mark></mark></mark></p>
<p>目的操作数是内存地址：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/194209671b306b8380b601d6be27d590-166833015581862.png" class="">
<p>目的操作数给出的是该位串在在内存中的第一个字节的地址，源操作数指定了可以访问的串的最大长度，若源操作数是16位的，则目的操作数即位串最大可以达到<strong>2^16</strong>个比特。</p>
<h2 id="21-空闲页搜索和分配的具体过程"><a href="#21-空闲页搜索和分配的具体过程" class="headerlink" title="21. 空闲页搜索和分配的具体过程"></a>21. 空闲页搜索和分配的具体过程</h2><p>接上一节，查看例程<strong>allocate_a_4k_page</strong>：</p>
<pre><code class="assembly">SECTION core_data vstart=0                  ;系统核心的数据段

    ......
    ......
    
    page_bit_map    db  0xff,0xff,0xff,0xff,0xff,0xff,0x55,0x55
                    db  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
                    db  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
                    db  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
                    db  0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55
                    db  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
                    db  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
                    db  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
    page_map_len	equ		$-page_bit_map

    ......
    ......
    ......

    allocate_a_4k_page:			;分配一个4KB的页
                                ;输入：无
                                ;输出：EAX=页的物理地址
                                ;每个页的状态可以从页映射位串中获得
    push ebx
    push ecx
    push edx
    push ds
    
    mov eax,core_data_seg_sel
    mov ds,eax		;指向内核数据段，以便指向页映射位串
    
    xor eax,eax		;循环，从头开始搜索位串，查找空闲的页
                    ;从页映射位串中找到第一个为0的比特
                    ;记下在整个位串中的位置
.b1:
    bts [page_bit_map],eax	;搜索位串，寻找第一个为0的比特
                            ;每次搜索的比特位的值都会传送到CF位
                            ;并且位串中的这个比特位被置1
    jnc .b2		;若CF=0，表示找到了空闲的页面，转到 .b2处执行，
                ;若CF=1，表示当前比特对应的页面被分配过了，还得继续查找。
    inc eax
    cmp eax,page_map_len*8		;page_map_len是位串的字节长度
                                ;乘以8换算成二进制比特位的数量
    jl .b1		;若没有超过，小于关系成立，转移到标号 .b1 处重新查找空闲页
                ;若超过了位串最大长度，小于关系不成立，打印文本，停机
    mov ebx,message_3
    call sys_routine_seg_sel:put_string
    hlt					;没有可以分配的页，停机
    
.b2:					;一旦找到空闲页，到达此处
                        ;EAX保存代表空闲页的那个比特位的索引号
                        ;将这个索引号乘以0x1000、4096就得到所应对的那个页的物理地址
    shl eax,12			;乘以4096（0x1000）
    
    pop ds
    pop edx
    pop ecx
    pop ebx
    
    ret
</code></pre>
<p>内存分配的全过程：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/5837f70290e6bb72a757e1bcef580a32-166833015581863.png" class="">


<h2 id="22-确立内核任务并开始创建用户任务"><a href="#22-确立内核任务并开始创建用户任务" class="headerlink" title="22. 确立内核任务并开始创建用户任务"></a>22. 确立内核任务并开始创建用户任务</h2><p>接上一节，回到内核<strong>start</strong>流程中<br>在<strong>TSS</strong>中登记必要项：</p>
<pre><code class="assembly">         ;在程序管理器的TSS中设置必要的项目
         mov word [es:ecx+0],0              ;反向链=0
         mov eax,cr3
         mov dword [es:ecx+28],eax          ;登记CR3(PDBR)
         mov word [es:ecx+96],0             ;没有LDT。处理器允许没有LDT的任务。
         mov word [es:ecx+100],0            ;T=0
         mov word [es:ecx+102],103          ;没有I/O位图。0特权级事实上不需要。
                                            ;不需要0、1、2特权级堆栈。0特级不
                                            ;会向低特权级转移控制。 
</code></pre>
<p>其中<strong>TSS</strong>还有其他信息没有填写，这些信息会在处理器进行第一次任务切换时自动填写。<br>接着创建<strong>TSS</strong>描述符、加载当前任务到<strong>TR</strong>寄存器中。<br>接着创建用户任务的<strong>TCB</strong>并加载到<strong>TCB</strong>的链表中、接着使用例程<strong>load_relocate_program</strong>创建用户任务相关内容。</p>
<h2 id="23-用户任务的内存分配策略"><a href="#23-用户任务的内存分配策略" class="headerlink" title="23. 用户任务的内存分配策略"></a>23. 用户任务的内存分配策略</h2><p>创建用户任务的第一步就是分配内存，将用户任务的程序加载进来。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/aca041c9ac0123cdb24af86c9edcd428-166833015581864.png" class="">
<p>当前正在执行内核的页目录表和页表，也就无法通过用户任务的页目录表和页表来访问内存，也不能切换到用户任务的页目录表和页表，切换之后内核就不能执行下去了。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/dd2b5a8684bfc62701272aea8478fbf0-166833015581865.png" class="">
<p>先给出内核任务、用户任务如何将虚拟地址空间映射到物理地址空间的：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/6fd5cdbb83920e3cf30528b36302925c-166833015581866.png" class="">
<p>其中内核与内核任务是共享高2GB空间的，所以在所有任务的页目录的高端都是一样的，在内核的页表中，既包含了内核所占用的物理页面，也包含了内核任务私有的物理页面。不过没有关系，因为只有内核任务才会使用页目录表的高2GB的表项，用户任务只会使用页目录低2GB的表项。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/349244ce1593efe244c1b0adc27561fd-166833015581867.png" class="">
<p>在内核任务的虚拟内存的低2GB是未使用的，那么对应内核任务的页目录中低一半的表项也是未使用的。</p>
<p>那么在创建用户任务时可以先在内核任务的虚拟空间的低一半分配内存，即使用页目录的低一半创建页目录表项，同时也会创建一些与这部分对应的页表并分配物理页。</p>
<p>因为是在创建用户任务，所以还会从硬盘中读出用户任务，写入分配来的这些物理页中。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/f4f000bbf6183222289074429bf531a0-166833015581868.png" class="">
<p>等这些工作完成之后，将内核任务的页目录表复制一份，作为被创建的用户任务的页目录表。此时用户任务的高一半指向内核的页表，低一半指向刚才创建的用户任务的页表。再复制之后，将内核任务的低一半页目录表清空。</p>
<h2 id="24-清空内核任务页目录表的前半部分并刷新TLB"><a href="#24-清空内核任务页目录表的前半部分并刷新TLB" class="headerlink" title="24. 清空内核任务页目录表的前半部分并刷新TLB"></a>24. 清空内核任务页目录表的前半部分并刷新TLB</h2><p>接上一节，进入例程<strong>load_relocate_program</strong>，加载重定位用户程序，并创建用户任务。本节代码如下：</p>
<pre><code class="assembly">load_relocate_program:                      ;加载并重定位用户程序
                                            ;输入: PUSH 逻辑扇区号
                                            ;      PUSH 任务控制块基地址
                                            ;输出：无 
         pushad
      
         push ds
         push es
      
         mov ebp,esp                        ;为访问通过堆栈传递的参数做准备
      
         mov ecx,mem_0_4_gb_seg_sel
         mov es,ecx

         ;清空当前页目录的前半部分（对应低2GB的局部地址空间）
         mov ebx,0xfffff000
         xor esi,esi
  .clsp:
         mov dword [es:ebx+esi*4],0x00000000
         inc esi
         cmp esi,512
         jl .clsp

         mov ebx,cr3                        ;刷新TLB
         mov cr3,ebx
                                                       
</code></pre>
<p>开启页部件时，页部件使用页目录和页表将线性地址转换为物理地址。而访问页目录表和页表是耗时的，因此把页表项提前存放到处理器中可以加快地址转换的速度，为此在处理器内部特地构造了一个高速缓存装置<strong>（Transaction Lookaside Buffer）</strong>。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/07556a53fea08215d82d60162499308e-166833015581969.png" class="">

<ul>
<li>处理器用线性地址的<strong>高20位</strong>查找<strong>TLB</strong>中的行，查找标记相同的行。找到之后就使用其数据部分的<strong>页物理地址</strong>转换当前线性地址</li>
<li>若查找不成功，则处理器还要访问内存中的页目录表和页表，找到对应的页表项，将其填写到<strong>TLB</strong>中。</li>
</ul>
<p><strong>TLB</strong>的容量不大，若装满之后还需要置换掉那些使用较少的条目。<strong>TLB</strong>中的属性位来自于页表项如<strong>D位</strong>。访问权来自于页目录项，如<strong>RW位</strong>、<strong>US位</strong>，具体取页目录项还是页表中的值，若页目录的<strong>RW = 0</strong>、页表项的<strong>RW = 1</strong>，按照<strong>RW = 0</strong>执行，即取最严格的权限执行 （等于是将访问权进行<strong>与操作</strong>）。</p>
<p>处理器仅仅缓存那些<strong>P位 = 1</strong>的页表项，而且<strong>TLB</strong>的工作和<strong>CR3</strong>寄存器的<strong>PCD、PWT</strong>无关，另外对于页表项的修改不会同时反映到<strong>TLB</strong>中。</p>
<p>如果内存表中的页表项已经修改，对应<strong>TLB</strong>中的条目还没有被更新，那么转换后的物理地址必定是错误的。</p>
<p>在本章里，内核任务页目录表的前一半用于创建用户任务，所以是频繁更新的，在创建用户任务时，必须先清除这一部分页目录项并刷新<strong>TLB</strong>。否则处理器将使用缓存的页表项访问内存，将会产生错误。</p>
<p><strong>TLB</strong>的内容或条目不可由软件直接访问的，所以不能直接更改或刷新它的内容，但是有其它办法刷新，比如将<strong>CR3</strong>的内容读出再原样写入，这样就会使得<strong>TLB</strong>中的所有条目失效。当任务切换时因为需要从新任务的<strong>TSS</strong>中加载<strong>CR3</strong>，这样会隐式的导致<strong>TLB</strong>的所有条目无效并重新刷新。</p>
<p>上述方法对那些<strong>G位 = 1</strong>的表项是无效的，被设置为全局的页表项应该始终被缓存在<strong>TLB</strong>中，在前面我们已经清空了页目录表的前半部分，为了使<strong>TLB</strong>的条目失效，需要重新加载<strong>CR3</strong>.</p>
<h2 id="25-为用户任务分配内存并创建LDT"><a href="#25-为用户任务分配内存并创建LDT" class="headerlink" title="25. 为用户任务分配内存并创建LDT"></a>25. 为用户任务分配内存并创建LDT</h2><p>接上一节，在清空内核任务页目录表的前半部分并刷新了<strong>TLB</strong>之后，就可以分配内存并加载用户程序了，本节代码如下：</p>
<pre><code class="assembly">mov esi,[ebp+11*4]                 ;从堆栈中取得TCB的基地址

         ;以下申请创建LDT所需要的内存
         mov ebx,esi
         mov ecx,160                        ;允许安装20个LDT描述符
         call sys_routine_seg_sel:task_alloc_memory
         mov [es:esi+0x0c],ecx              ;登记LDT基地址到TCB中
         mov word [es:esi+0x0a],0xffff      ;登记LDT初始的界限到TCB中  
</code></pre>
<p>申请内存：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/fc207a4863236bff10f6dae579f1fc5e-166833015581970.png" class="">
<p><strong>情况1</strong>：</p>
<ul>
<li>对于任何一个正在执行的任务，若要申请额外的内存空间，可以调用例程<strong>allocate_memory</strong></li>
<li>例程<strong>allocate_memory</strong>需要调用<strong>task_allocate_memory</strong>，需要当前任务自己的TCB作为参数，所以例程<strong>allocate_memory</strong>需要获得当前任务控制块<strong>TCB</strong></li>
<li>例程<strong>task_allocate_memory</strong>需要访问<strong>TCB</strong>，来确定本次内存分配器始于哪个线性地址，并根据分配的内存数量确定一个地址范围</li>
<li>若当前任务是内核任务，那么这个线性地址范围一定位于虚拟线性地址的高端、普通任务则位于虚拟线性地址的低端</li>
<li>确定线性地址范围之后，调用<strong>alloc_inst_a_page</strong>来分配和安装与线性地址相关的物理页。首先检查当前任务的页目录表和页表，看一下表项是否存在。存在说明之前分配过，直接返回</li>
<li>不存在，则调用例程<strong>allocate_a_4k_page</strong>在物理页中查找并返回空闲的物理页地址</li>
<li>无论如何，例程<strong>alloc_inst_a_page</strong>都是在当前任务的页目录和页表中登记线性地址与物理页的对应关系。</li>
</ul>
<p><strong>情况2</strong>：<br>在一个任务被创建并开始执行之前，需要先创建这个任务自己的虚拟内存空间，并在这个虚拟内存空间里分配用来加载这个任务的代码和数据。用户任务的创建是内核任务的工作，所以需要有内核任务代替用户任务来完成内存的创建和分配。</p>
<p>因为这个原因，需要借用内核任务页目录的前半部分来分配内存，内存分配完成用户任务创建之后，再将内核任务的页目录表复制一份给用户任务就可以了</p>
<p>有内核任务代替用户任务分配内存时，内核任务需要拿着用户任务的<strong>TCB</strong>来调用例程<strong>task_allocate_memory</strong>。毕竟内存分配是在用户任务自己的虚拟空间中进行，需要从用户任务自己的<strong>TCB</strong>中取得本次分配需要的线性地址。虽然是为用户任务分配内存，但却是在内核任务的页目录表中登记了页目录表项，这没关系后面直接复制一份即可。</p>
<h2 id="26-用户程序的加载和重定位"><a href="#26-用户程序的加载和重定位" class="headerlink" title="26. 用户程序的加载和重定位"></a>26. 用户程序的加载和重定位</h2><p>上一节已经为<strong>LDT</strong>分配了内存，接下来就是从硬盘读取用户程序</p>
<p>加载用户程序头部读取用户程序总字节数、将用户程序总字节数换算为总扇区数、循环读取用户程序剩余部分、建立用户程序的段描述符：</p>
<p>用户程序的<strong>SALT</strong>在用户程序头部段中，但是用户程序头部段暂时不能访问，因为当前任务是内核任务而不是用户任务</p>
<p>现在考虑一下用户程序什么能访问、什么不能访问，我们现在是在内核虚拟空间的低2GB虚拟空间里分配内存并加载用户程序，所以加载之后的内容是可以访问到的，不过现在是借助内核地址空间来访问的。</p>
<p>现在创建了用户程序的段选择子和段描述符，但是不能使用，因为这些段位于用户任务的<strong>LDT</strong>中，只有<strong>LDTR</strong>寄存器指向这个<strong>LDT</strong>才能访问这些段。但是当前是在内核任务中，是没有<strong>LDT</strong>的</p>
<p>之后重定位<strong>SALT</strong>、创建用户程序调用门0、1、2特权级的栈、在<strong>GDT</strong>中登记<strong>LDT</strong>描述符、创建用户程序的<strong>TSS</strong>、登记基本的<strong>TSS</strong>表格内容、访问用户程序头部段，获取数据填充<strong>TSS</strong>、在<strong>GDT</strong>中登记<strong>TSS</strong>描述符、创建用户任务的页目录，最后返回调用者。</p>
<h2 id="27-用户任务页目录表的创建和访问以及INVLPG指令"><a href="#27-用户任务页目录表的创建和访问以及INVLPG指令" class="headerlink" title="27. 用户任务页目录表的创建和访问以及INVLPG指令"></a>27. 用户任务页目录表的创建和访问以及INVLPG指令</h2><p>接上一节，当用户任务的加载和创建结束时，需要将内核任务的页目录表复制给用户任务。代码如下：</p>
<pre><code class="assembly">         ;创建用户任务的页目录
         ;注意！页的分配和使用是由页位图决定的，可以不占用线性地址空间
         call sys_routine_seg_sel:create_copy_cur_pdir
         mov ebx,[es:esi+0x14]              ;从TCB中获取TSS的线性地址
         mov dword [es:ebx+28],eax          ;填写TSS的CR3(PDBR)域   
</code></pre>
<p>例程<strong>create_copy_cur_pdir</strong>：</p>
<pre><code class="assembly">create_copy_cur_pdir		;创建新页目录，并复制当前页目录内容
                      		;输入：无
                          	;输出：EAX=新页目录的物理地址
    push ds
    push es
    push esi
    push edi
    push ebx
    push ecx
    
    mov ebx,mem_0_4_gb_seg_sel     ;指向4G字节的段，为访问两个
    mov ds,ebx                     ;页目录表做准备
    mov es,ebx
    
    call allocate_a_4k_page
    mov ebx,eax		;EAX时这个页的基地址
    or ebx,0x00000007
    mov [0xfffffff8],ebx
    
    invlpg [0xfffffff8]		;刷新处理器的TLB中的条目
                            ;这个页目录项位于内核任务的页目录表中 
                            ;每当我们创建一个新的用户任务时，都用它来指向新任务的页目录表
                            ;修改这个表项时，修改的是内存中的，其在TLB中还有一个缓存
                            ;这个缓存的内容通常指向上一个任务的页目录表，因为我们在反复创建新任务
                            ;所以需要强制刷新这个缓存，与当前内存中的表项保持一致
                            
    mov esi,0xfffff000		;ESI-&gt;当前页目录的线性地址
    mov edi,0xffffe000		;EDI-&gt;新页目录的线性地址
    mov ecx,1024			;ECX=要复制的目录项数
    cld						;传送方向为正，从底到高
    repe movsd     			;需要使用两个段寄存器
                            ;movsd表示每次传送一个字
                            ;源操作数位于DS、目的操作数位于ES中
    
    pop ecx
    pop ebx
    pop edi
    pop esi
    pop es
    pop ds
    
    retf
</code></pre>
<p>为了能访问到这个4K字节页，把其物理地址登记到当前页目录表的倒数第二个表项中，即表内偏移<strong>0xFF8</strong>地址处。这个表项的线性地址为：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/86a5e81c6f38a69aa6a7f214ed2c8fd9-166833015581971.png" class="">
<p>所以程序中，将附加了属性的页地址登记到这个线性地址处<strong>mov [0xfffffff8], ebx</strong>。</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/70d154c87cbdd47bdabab6d6f7a1f256-166833015581972.png" class="">
<p>其中指令<strong>invlpg(Invalidate TLB Entry)<strong>用于刷新</strong>TLB</strong>中的单个条目。<strong>TLB</strong>是一个附加的硬件机构，只有处理器正常访问内存时才会导致它的填充和更新。</p>
<p>这条指令是特权指令，在保护模式下执行的特权级必须是0，此指令不影响任何标志位。</p>
<p>为什么新页目录表的线性地址是<strong>0xFFFFE000</strong>呢？</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/944f6f04ee6e0be26a785c13e719da30-166833015581973.png" class="">

<h2 id="28-第二个用户任务的创建和分页模式下的任务切换"><a href="#28-第二个用户任务的创建和分页模式下的任务切换" class="headerlink" title="28. 第二个用户任务的创建和分页模式下的任务切换"></a>28. 第二个用户任务的创建和分页模式下的任务切换</h2><p>在加载和创建用户任务之后，处于就绪状态，随时可以执行。在本章中任务切换是自动进行的，是由一个实时时钟信号驱动的，时钟芯片每秒钟发出一个中断信号，中断发生时处理器执行设置好的中断处理过程。这个中断处理过程就用于执行任务切换。</p>
<p>中断处理过程就是<strong>rtm_0x70_interrupt_handle</strong>例程，调用<strong>initiate_task_switch</strong>从<strong>TCB</strong>链表中找到当前状态为忙的任务将其状态改为就绪、再找到后面第一个就绪的任务将其状态设置为忙，切换任务执行。</p>
<p>一旦内核任务重新执行时，将执行后续指令：</p>
<pre><code class="assembly">    push dword 50                      	;用户程序位于逻辑50扇区
    push ecx                           	;压入任务控制块起始线性地址 
    call load_relocate_program
    call append_to_tcb_link            	;将此TCB添加到TCB链中
                                        ;此时有2个任务轮流执行
    
    
    ;可以创建更多的任务，例如：
    mov ecx,0x4a
    call sys_routine_seg_sel:allocate_memory
    mov word [es:ecx+0x04],0           	;任务状态：空闲
    mov dword [es:ecx+0x46],0          	;任务内可用于分配的初始线性地址
    
    push dword 100                     	;用户程序位于逻辑100扇区
    push ecx                           	;压入任务控制块起始线性地址
    
    call load_relocate_program
    call append_to_tcb_link            	;将此TCB添加到TCB链中
                                        ;此时有2个任务轮流执行
    
.do_switch:
    mov ebx,core_msg2
    call sys_routine_seg_sel:put_string
    
    ;清理已经终止的任务，并回收它们占用的资源
    call sys_routine_seg_sel:do_task_clean
    
    hlt			;停机之后，任何时候发生中断
                ;处理器将会被唤醒继续执行任务切换
    
    jmp .do_switch
</code></pre>
<p>用户程序和上一章相同：<strong>用户程序1</strong>打印<strong>，，，，，，…<strong>、</strong>用户程序2</strong>打印<strong>cccccc…</strong></p>
<pre><code class="assembly">SECTION code vstart=0
start:
    ;任务启动时，DS指向头部段，也不需要设置堆栈 
    mov eax,ds
    mov fs,eax
    
    mov ax,[data_seg]
    mov ds,ax
    
.do_prn:
    mov ebx,message_1
    call far [fs:PrintString]
    jmp .do_prn
    
    call far [fs:TerminateProgram]      ;退出，并将控制权返回到核心 
    
code_end:
</code></pre>
<h2 id="29-分页模式下多任务切换的演示和调试"><a href="#29-分页模式下多任务切换的演示和调试" class="headerlink" title="29. 分页模式下多任务切换的演示和调试"></a>29. 分页模式下多任务切换的演示和调试</h2><p>加载程序：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/dd6b2d1cf65101ab1157fdbf959c2e12-166833015581974.png" class="">

<p><strong>Virtual Box</strong>虚拟机：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/7c427b058ef8287c6591c609d62a8c86-166833015581975.png" class="">

<p><strong>Bochs</strong>虚拟机：<br>设置断点：<mark>b 0x7c00</mark><br>执行：<mark>c</mark><br>设置断点：<mark>modebp</mark>，会在模式切换时停下<br>设置断点在进入内核的时候：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/bc66e79cf2decf543a4c0de3902f257b-166833015581976.png" class="">
<p>设置断点在创建第一个用户程序之前：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/2abbb8cf38ef0b7bc71cb4ff85c61f1c-166833015581977.png" class="">
<p>当前分页功能是关闭的：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/151a3202b0f470cfe608ee6cdc4f0e55-166833015581978.png" class="">
<p>执行到创建第一个用户程序这个断点之前：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/87d023f2b13c30f6f0248ee085d7f933-166833015581979.png" class="">
<p><strong>page</strong>命令解析线性地址是如何映射的：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/2d207c40d4ed4aad351b0574c350c05c-166833015581980.png" class="">

<ul>
<li><strong>PDE行</strong>：第一行是该线性地址在页目录表中对应的表项，该表项填写了该线性地址对应页表的物理地址是<strong>0x21000</strong>，后面的<strong>023</strong>是属性信息，大写是1、小写是0</li>
<li><strong>PTE行</strong>：第二行是该线性地址在页表内的登记项，页的物理地址是0、属性信息是3</li>
<li>从这两行直到线性地址中<strong>0</strong>对应的物理地址也是<strong>0</strong></li>
</ul>
<p>再看一下高端线性地址的对应：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/2232d584b1105c1c111a6d24dc4232bc-166833015581981.png" class="">

<ul>
<li>页表物理地址是<strong>0x21000</strong></li>
<li>这个物理页对应的物理页地址为<strong>0</strong>，之前把内核从低端映射到高端，那么这个地址就是高端的起始地址</li>
</ul>
<p>进入例程<strong>load_relocate_program</strong>：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/93f55c2f8dc74acbb1ea7606ee60f989-166833015581982.png" class="">
<p>设置断点在<strong>ret 8</strong>处：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/4cefb3a82b2456df50beb419a43bd04c-166833015581983.png" class="">
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/08d72b71dd46721eaa0f9158add23515-166833015581984.png" class="">
<p>前面是内核任务为用户任务设置的地址对应关系。</p>
<p>此时用户任务的线性地址<strong>0</strong>被映射为<strong>0x35000</strong>：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/2485ee1c3461410a66d0c7eef09f5509-166833015581985.png" class="">
<p><strong>blist</strong>命令查看设置过的断点信息：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/587119267467e85e47a9d50f2273e939-166833015581986.png" class="">
<p>第二个任务创建之后，线性地址<strong>0</strong>被映射为<strong>0x101000</strong></p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/f52abfb2fbdea7ddf2b8763e5a182598-166833015581987.png" class="">
<p>即对于不同的线性地址会被映射到不同的页中，其物理地址是不同的。</p>
<p>执行信息：</p>
<img lazyload="" src="/images/loading.svg" data-src="/2022/12/11/31-%E5%88%86%E9%A1%B5%E5%92%8C%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E9%85%8D/image-20221113170249308.png" class="" title="image-20221113170249308">

		</div>

		
		<div class="post-copyright-info w-full my-8 px-2 sm:px-6 md:px-8">
			<div class="article-copyright-info-container">
    <ul>
        <li><strong>标题:</strong> 分页和动态页面分配</li>
        <li><strong>作者:</strong> xiaoeryu</li>
        <li><strong>创建于
                :</strong> 2022-12-11 22:49:00</li>
        
            <li>
                <strong>更新于
                    :</strong> 2023-10-04 16:56:25
            </li>
        
        <li>
            <strong>链接:</strong> https://github.com/xiaoeryu/2022/12/11/31-分页和动态页面分配/
        </li>
        <li>
            <strong>
                版权声明:
            </strong>
            

            
                本文章采用 <a class="license" target="_blank" rel="noopener" href="https://creativecommons.org/licenses/by-nc-sa/4.0">CC BY-NC-SA 4.0</a> 进行许可。
            
        </li>
    </ul>
</div>

		</div>
		

		
		<ul class="post-tags-box text-lg mt-1.5 flex-wrap justify-center flex md:hidden">
			
			<li class="tag-item mx-0.5">
				<a href="/tags/x86%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/">#x86内存管理</a>&nbsp;
			</li>
			
		</ul>
		

		

		
		<div class="article-nav my-8 flex justify-between items-center px-2 sm:px-6 md:px-8">
			
			<div class="article-prev border-border-color shadow-redefine-flat shadow-shadow-color-2 rounded-medium px-4 py-2 hover:shadow-redefine-flat-hover hover:shadow-shadow-color-2">
				<a class="prev" rel="prev" href="/2022/12/11/32-%E5%B9%B3%E5%9D%A6%E6%A8%A1%E5%9E%8B/">
					<span class="left arrow-icon flex justify-center items-center">
						<i class="fa-solid fa-chevron-left"></i>
					</span>
					<span class="title flex justify-center items-center">
						<span class="post-nav-title-item">平坦模型</span>
						<span class="post-nav-item">上一篇</span>
					</span>
				</a>
			</div>
			
			
			<div class="article-next border-border-color shadow-redefine-flat shadow-shadow-color-2 rounded-medium px-4 py-2 hover:shadow-redefine-flat-hover hover:shadow-shadow-color-2">
				<a class="next" rel="next" href="/2022/12/11/30-%E4%B8%AD%E6%96%AD%E5%92%8C%E5%BC%82%E5%B8%B8%E7%9A%84%E5%A4%84%E7%90%86%E4%B8%8E%E6%8A%A2%E5%8D%A0%E5%BC%8F%E5%A4%9A%E4%BB%BB%E5%8A%A1/">
					<span class="title flex justify-center items-center">
						<span class="post-nav-title-item">中断和异常的处理与抢占式多任务</span>
						<span class="post-nav-item">下一篇</span>
					</span>
					<span class="right arrow-icon flex justify-center items-center">
						<i class="fa-solid fa-chevron-right"></i>
					</span>
				</a>
			</div>
			
		</div>
		


		
		<div class="comment-container px-2 sm:px-6 md:px-8 pb-8">
			<div class="comments-container mt-10 w-full ">
    <div id="comment-anchor" class="w-full h-2.5"></div>
    <div class="comment-area-title w-full my-1.5 md:my-2.5 text-xl md:text-3xl font-bold">
        评论
    </div>
    

        
            


        
    
</div>

		</div>
		
	</div>

	
	<div class="toc-content-container">
		<div class="post-toc-wrap">
	<div class="post-toc">
		<div class="toc-title">目录</div>
		<div class="page-title">分页和动态页面分配</div>
		<ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#01-%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F%E4%B8%8B%E7%9A%84%E6%AE%B5%E5%BC%8F%E8%99%9A%E6%8B%9F%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86"><span class="nav-text">01. 保护模式下的段式虚拟内存管理</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#02-%E6%AF%8F%E4%B8%AA%E4%BB%BB%E5%8A%A1%E7%8B%AC%E7%AB%8B%E7%9A%84%E8%99%9A%E6%8B%9F%E5%86%85%E5%AD%98"><span class="nav-text">02. 每个任务独立的虚拟内存</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#03-%E7%89%A9%E7%90%86%E5%86%85%E5%AD%98%E7%9A%84%E5%88%86%E9%A1%B5%E4%BB%A5%E5%8F%8A%E6%AE%B5%E5%88%B0%E9%A1%B5%E7%9A%84%E6%8B%86%E5%88%86"><span class="nav-text">03. 物理内存的分页以及段到页的拆分</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#04-%E5%A4%84%E7%90%86%E5%99%A8%E7%9A%84%E6%AE%B5%E9%83%A8%E4%BB%B6%E5%92%8C%E9%A1%B5%E9%83%A8%E4%BB%B6"><span class="nav-text">04. 处理器的段部件和页部件</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#05-%E4%BB%8E%E7%BA%BF%E6%80%A7%E5%9C%B0%E5%9D%80%E5%88%B0%E7%89%A9%E7%90%86%E5%9C%B0%E5%9D%80%E7%9A%84%E8%BD%AC%E6%8D%A2%E8%BF%87%E7%A8%8B"><span class="nav-text">05. 从线性地址到物理地址的转换过程</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#06-%E9%A1%B5%E7%9B%AE%E5%BD%95%E5%92%8C%E9%A1%B5%E8%A1%A8%E5%8F%8A%E5%85%B6%E5%9C%B0%E5%9D%80%E8%BD%AC%E6%8D%A2%E8%BF%87%E7%A8%8B"><span class="nav-text">06. 页目录和页表及其地址转换过程</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#07-%E8%AE%BE%E8%AE%A1%E5%86%85%E6%A0%B8%E7%9A%84%E9%A1%B5%E7%9B%AE%E5%BD%95%E5%92%8C%E9%A1%B5%E8%A1%A8"><span class="nav-text">07. 设计内核的页目录和页表</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#08-%E9%A1%B5%E7%9B%AE%E5%BD%95%E9%A1%B9%E5%92%8C%E9%A1%B5%E8%A1%A8%E9%A1%B9%E7%9A%84%E7%BB%84%E6%88%90%E6%A0%BC%E5%BC%8F"><span class="nav-text">08. 页目录项和页表项的组成格式</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#09-%E5%88%9B%E5%BB%BA%E5%86%85%E6%A0%B8%E7%9A%84%E9%A1%B5%E8%A1%A8%E5%B9%B6%E5%88%9D%E5%A7%8B%E5%8C%96%E4%BD%8E%E7%AB%AF1MB%E5%AF%B9%E5%BA%94%E7%9A%84%E9%A1%B5%E8%A1%A8%E9%A1%B9"><span class="nav-text">09. 创建内核的页表并初始化低端1MB对应的页表项</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#10-%E8%AE%BE%E7%BD%AE%E6%8E%A7%E5%88%B6%E5%AF%84%E5%AD%98%E5%99%A8CR3%E5%92%8CCR0%E5%BC%80%E5%90%AF%E5%88%86%E9%A1%B5%E5%8A%9F%E8%83%BD"><span class="nav-text">10. 设置控制寄存器CR3和CR0开启分页功能</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#11-%E5%9C%A8%E8%B0%83%E8%AF%95%E5%99%A8%E4%B8%AD%E8%A7%82%E5%AF%9F%E9%A1%B5%E7%9B%AE%E5%BD%95%E8%A1%A8%E5%92%8C%E9%A1%B5%E8%A1%A8"><span class="nav-text">11. 在调试器中观察页目录表和页表</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#12-%E5%87%86%E5%A4%87%E5%B0%86%E5%86%85%E6%A0%B8%E6%98%A0%E5%B0%84%E5%88%B0%E8%99%9A%E6%8B%9F%E5%86%85%E5%AD%98%E7%9A%84%E9%AB%98%E7%AB%AF"><span class="nav-text">12. 准备将内核映射到虚拟内存的高端</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#13-%E5%9C%A8%E5%88%86%E9%A1%B5%E6%9C%BA%E5%88%B6%E4%B8%8B%E8%AE%BF%E9%97%AE%E9%A1%B5%E7%9B%AE%E5%BD%95%E8%A1%A8%E8%87%AA%E8%BA%AB"><span class="nav-text">13. 在分页机制下访问页目录表自身</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#14-%E4%BD%BF%E5%86%85%E6%A0%B8%E5%9C%A8%E8%99%9A%E6%8B%9F%E5%86%85%E5%AD%98%E9%AB%98%E7%AB%AF%E7%9A%84%E6%98%A0%E5%B0%84%E7%94%9F%E6%95%88"><span class="nav-text">14. 使内核在虚拟内存高端的映射生效</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#15-%E4%B8%BA%E5%86%85%E6%A0%B8%E4%BB%BB%E5%8A%A1%E5%88%9B%E5%BB%BA%E4%BB%BB%E5%8A%A1%E6%8E%A7%E5%88%B6%E5%9D%97TCB"><span class="nav-text">15. 为内核任务创建任务控制块TCB</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#16-%E4%B8%BA%E5%86%85%E6%A0%B8%E4%BB%BB%E5%8A%A1%E7%9A%84TSS%E5%88%86%E9%85%8D%E5%86%85%E5%AD%98%E7%A9%BA%E9%97%B4"><span class="nav-text">16. 为内核任务的TSS分配内存空间</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#17-%E5%A4%84%E7%90%86%E4%B8%8E%E7%BA%BF%E6%80%A7%E5%9C%B0%E5%9D%80%E5%AF%B9%E5%BA%94%E7%9A%84%E9%A1%B5%E7%9B%AE%E5%BD%95%E9%A1%B9%E5%92%8C%E9%A1%B5%E8%A1%A8%E9%A1%B9"><span class="nav-text">17. 处理与线性地址对应的页目录项和页表项</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#18-%E6%A0%B9%E6%8D%AE%E9%9C%80%E8%A6%81%E5%88%86%E9%85%8D%E7%89%A9%E7%90%86%E9%A1%B5%E5%B9%B6%E8%AE%BE%E7%BD%AE%E9%A1%B5%E8%A1%A8%E9%A1%B9"><span class="nav-text">18. 根据需要分配物理页并设置页表项</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#19-%E7%89%A9%E7%90%86%E5%86%85%E5%AD%98%E7%9A%84%E9%A1%B5%E9%9D%A2%E7%AE%A1%E7%90%86%E5%92%8C%E9%A1%B5%E6%98%A0%E5%B0%84%E4%BD%8D%E4%B8%B2"><span class="nav-text">19. 物理内存的页面管理和页映射位串</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#20-%E7%A9%BA%E9%97%B2%E9%A1%B5%E7%9A%84%E6%90%9C%E7%B4%A2%E5%92%8CBTS%E6%8C%87%E4%BB%A4"><span class="nav-text">20. 空闲页的搜索和BTS指令</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#21-%E7%A9%BA%E9%97%B2%E9%A1%B5%E6%90%9C%E7%B4%A2%E5%92%8C%E5%88%86%E9%85%8D%E7%9A%84%E5%85%B7%E4%BD%93%E8%BF%87%E7%A8%8B"><span class="nav-text">21. 空闲页搜索和分配的具体过程</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#22-%E7%A1%AE%E7%AB%8B%E5%86%85%E6%A0%B8%E4%BB%BB%E5%8A%A1%E5%B9%B6%E5%BC%80%E5%A7%8B%E5%88%9B%E5%BB%BA%E7%94%A8%E6%88%B7%E4%BB%BB%E5%8A%A1"><span class="nav-text">22. 确立内核任务并开始创建用户任务</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#23-%E7%94%A8%E6%88%B7%E4%BB%BB%E5%8A%A1%E7%9A%84%E5%86%85%E5%AD%98%E5%88%86%E9%85%8D%E7%AD%96%E7%95%A5"><span class="nav-text">23. 用户任务的内存分配策略</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#24-%E6%B8%85%E7%A9%BA%E5%86%85%E6%A0%B8%E4%BB%BB%E5%8A%A1%E9%A1%B5%E7%9B%AE%E5%BD%95%E8%A1%A8%E7%9A%84%E5%89%8D%E5%8D%8A%E9%83%A8%E5%88%86%E5%B9%B6%E5%88%B7%E6%96%B0TLB"><span class="nav-text">24. 清空内核任务页目录表的前半部分并刷新TLB</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#25-%E4%B8%BA%E7%94%A8%E6%88%B7%E4%BB%BB%E5%8A%A1%E5%88%86%E9%85%8D%E5%86%85%E5%AD%98%E5%B9%B6%E5%88%9B%E5%BB%BALDT"><span class="nav-text">25. 为用户任务分配内存并创建LDT</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#26-%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8A%A0%E8%BD%BD%E5%92%8C%E9%87%8D%E5%AE%9A%E4%BD%8D"><span class="nav-text">26. 用户程序的加载和重定位</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#27-%E7%94%A8%E6%88%B7%E4%BB%BB%E5%8A%A1%E9%A1%B5%E7%9B%AE%E5%BD%95%E8%A1%A8%E7%9A%84%E5%88%9B%E5%BB%BA%E5%92%8C%E8%AE%BF%E9%97%AE%E4%BB%A5%E5%8F%8AINVLPG%E6%8C%87%E4%BB%A4"><span class="nav-text">27. 用户任务页目录表的创建和访问以及INVLPG指令</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#28-%E7%AC%AC%E4%BA%8C%E4%B8%AA%E7%94%A8%E6%88%B7%E4%BB%BB%E5%8A%A1%E7%9A%84%E5%88%9B%E5%BB%BA%E5%92%8C%E5%88%86%E9%A1%B5%E6%A8%A1%E5%BC%8F%E4%B8%8B%E7%9A%84%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2"><span class="nav-text">28. 第二个用户任务的创建和分页模式下的任务切换</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#29-%E5%88%86%E9%A1%B5%E6%A8%A1%E5%BC%8F%E4%B8%8B%E5%A4%9A%E4%BB%BB%E5%8A%A1%E5%88%87%E6%8D%A2%E7%9A%84%E6%BC%94%E7%A4%BA%E5%92%8C%E8%B0%83%E8%AF%95"><span class="nav-text">29. 分页模式下多任务切换的演示和调试</span></a></li></ol>

	</div>
</div>
	</div>
	
</div>
			</div>

			
		</div>

		<div class="main-content-footer">
			<footer class="footer mt-5 py-5 h-auto text-base text-third-text-color relative border-t-2 border-t-border-color">
    <div class="info-container py-3 text-center">
        
        <div class="text-center">
            &copy;
            
              <span>2022</span>
              -
            
            2025&nbsp;&nbsp;<i class="fa-solid fa-heart fa-beat" style="--fa-animation-duration: 0.5s; color: #f54545"></i>&nbsp;&nbsp;<a href="/">xiaoeryu</a>
            
                
                <p class="post-count space-x-0.5">
                    <span>
                        共撰写了 112 篇文章
                    </span>
                    
                </p>
            
        </div>
        
            <script data-swup-reload-script src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
            <div class="relative text-center lg:absolute lg:right-[20px] lg:top-1/2 lg:-translate-y-1/2 lg:text-right">
                
                    <span id="busuanzi_container_site_uv" class="lg:!block">
                        <span class="text-sm">访问人数</span>
                        <span id="busuanzi_value_site_uv"></span>
                    </span>
                
                
                    <span id="busuanzi_container_site_pv" class="lg:!block">
                        <span class="text-sm">总访问量</span>
                        <span id="busuanzi_value_site_pv"></span>
                    </span>
                
            </div>
        
        <div class="relative text-center lg:absolute lg:left-[20px] lg:top-1/2 lg:-translate-y-1/2 lg:text-left">
            <span class="lg:block text-sm">由 <?xml version="1.0" encoding="utf-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="relative top-[2px] inline-block align-baseline" version="1.1" id="圖層_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="1rem" height="1rem" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve"><path fill="#0E83CD" d="M256.4,25.8l-200,115.5L56,371.5l199.6,114.7l200-115.5l0.4-230.2L256.4,25.8z M349,354.6l-18.4,10.7l-18.6-11V275H200v79.6l-18.4,10.7l-18.6-11v-197l18.5-10.6l18.5,10.8V237h112v-79.6l18.5-10.6l18.5,10.8V354.6z"/></svg><a target="_blank" class="text-base" href="https://hexo.io">Hexo</a> 驱动</span>
            <span class="text-sm lg:block">主题&nbsp;<a class="text-base" target="_blank" href="https://github.com/EvanNotFound/hexo-theme-redefine">Redefine v2.8.2</a></span>
        </div>
        
        
            <div>
                博客已运行 <span class="odometer" id="runtime_days" ></span> 天 <span class="odometer" id="runtime_hours"></span> 小时 <span class="odometer" id="runtime_minutes"></span> 分钟 <span class="odometer" id="runtime_seconds"></span> 秒
            </div>
        
        
            <script data-swup-reload-script>
                try {
                    function odometer_init() {
                    const elements = document.querySelectorAll('.odometer');
                    elements.forEach(el => {
                        new Odometer({
                            el,
                            format: '( ddd).dd',
                            duration: 200
                        });
                    });
                    }
                    odometer_init();
                } catch (error) {}
            </script>
        
        
        
    </div>  
</footer>
		</div>
	</div>

	
	<div class="post-tools">
		<div class="post-tools-container">
	<ul class="article-tools-list">
		<!-- TOC aside toggle -->
		
		<li class="right-bottom-tools page-aside-toggle">
			<i class="fa-regular fa-outdent"></i>
		</li>
		

		<!-- go comment -->
		
		<li class="go-comment">
			<i class="fa-regular fa-comments"></i>
		</li>
		
	</ul>
</div>
	</div>
	

	<div class="right-side-tools-container">
		<div class="side-tools-container">
	<ul class="hidden-tools-list">
		<li class="right-bottom-tools tool-font-adjust-plus flex justify-center items-center">
			<i class="fa-regular fa-magnifying-glass-plus"></i>
		</li>

		<li class="right-bottom-tools tool-font-adjust-minus flex justify-center items-center">
			<i class="fa-regular fa-magnifying-glass-minus"></i>
		</li>

		<li class="right-bottom-tools tool-dark-light-toggle flex justify-center items-center">
			<i class="fa-regular fa-moon"></i>
		</li>

		<!-- rss -->
		

		

		<li class="right-bottom-tools tool-scroll-to-bottom flex justify-center items-center">
			<i class="fa-regular fa-arrow-down"></i>
		</li>
	</ul>

	<ul class="visible-tools-list">
		<li class="right-bottom-tools toggle-tools-list flex justify-center items-center">
			<i class="fa-regular fa-cog fa-spin"></i>
		</li>
		
		<li class="right-bottom-tools tool-scroll-to-top flex justify-center items-center">
			<i class="arrow-up fas fa-arrow-up"></i>
			<span class="percent"></span>
		</li>
		
		
	</ul>
</div>
	</div>

	<div class="image-viewer-container">
	<img src="">
</div>

	
	<div class="search-pop-overlay">
	<div class="popup search-popup">
		<div class="search-header">
			<span class="search-input-field-pre">
				<i class="fa-solid fa-keyboard"></i>
			</span>
			<div class="search-input-container">
				<input autocomplete="off" autocorrect="off" autocapitalize="off" placeholder="站内搜索您需要的内容..." spellcheck="false" type="search" class="search-input">
			</div>
			<span class="popup-btn-close">
				<i class="fa-solid fa-times"></i>
			</span>
		</div>
		<div id="search-result">
			<div id="no-result">
				<i class="fa-solid fa-spinner fa-spin-pulse fa-5x fa-fw"></i>
			</div>
		</div>
	</div>
</div>
	

</main>



<script src="/js/build/libs/Swup.min.js"></script>

<script src="/js/build/libs/SwupSlideTheme.min.js"></script>

<script src="/js/build/libs/SwupScriptsPlugin.min.js"></script>

<script src="/js/build/libs/SwupProgressPlugin.min.js"></script>

<script src="/js/build/libs/SwupScrollPlugin.min.js"></script>

<script src="/js/build/libs/SwupPreloadPlugin.min.js"></script>

<script>
    const swup = new Swup({
        plugins: [
            new SwupScriptsPlugin({
                optin: true,
            }),
            new SwupProgressPlugin(),
            new SwupScrollPlugin({
                offset: 80,
            }),
            new SwupSlideTheme({
                mainElement: ".main-content-body",
            }),
            new SwupPreloadPlugin(),
        ],
        containers: ["#swup"],
    });
</script>




	
<script src="/js/build/tools/imageViewer.js" type="module"></script>

<script src="/js/build/utils.js" type="module"></script>

<script src="/js/build/main.js" type="module"></script>

<script src="/js/build/layouts/navbarShrink.js" type="module"></script>

<script src="/js/build/tools/scrollTopBottom.js" type="module"></script>

<script src="/js/build/tools/lightDarkSwitch.js" type="module"></script>

<script src="/js/build/layouts/categoryList.js" type="module"></script>



    
<script src="/js/build/tools/localSearch.js" type="module"></script>




    
<script src="/js/build/tools/codeBlock.js" type="module"></script>




    
<script src="/js/build/layouts/lazyload.js" type="module"></script>




    
<script src="/js/build/tools/runtime.js"></script>

    
<script src="/js/build/libs/odometer.min.js"></script>

    
<link rel="stylesheet" href="/assets/odometer-theme-minimal.css">




  
<script src="/js/build/libs/Typed.min.js"></script>

  
<script src="/js/build/plugins/typed.js" type="module"></script>








    
<script src="/js/build/libs/anime.min.js"></script>





    
<script src="/js/build/tools/tocToggle.js" type="module" data-swup-reload-script=""></script>

<script src="/js/build/layouts/toc.js" type="module" data-swup-reload-script=""></script>

<script src="/js/build/plugins/tabs.js" type="module" data-swup-reload-script=""></script>




<script src="/js/build/libs/moment-with-locales.min.js" data-swup-reload-script=""></script>


<script src="/js/build/layouts/essays.js" type="module" data-swup-reload-script=""></script>





	
</body>

</html>